gpt4 book ai didi

c++ - 为什么 std::is_convertible_v 返回 true 即使此转换不合法?

转载 作者:太空狗 更新时间:2023-10-29 22:54:05 25 4
gpt4 key购买 nike

我正在开发一个 C++ 项目,该项目需要使用类型自省(introspection)来确定模板的对象类型。这样做时,我遇到了一个不寻常的问题。我将根本问题归结为 std::is_convertible_v 所说的内容与实际上可以相互转换的类型之间的不匹配。这是一个演示问题的简化示例。

这是一个名为 LookForNested 的类型,它有一个模板构造函数,该构造函数在模板参数类型内部查找名为 NestedType 的嵌套类型。

struct LookForNested {
/* Look inside the argument type for a nested type. This won't
* compile if you invoke the constructor on a type that doesn't have
* a nested type with name NestedType.
*/
template <typename T> LookForNested(const T&) {
typename T::NestedType x;
}
};

令人惊讶的是,此 static_assert 失败了,即使您无法使用整数初始化 LookForNested:

static_assert(!std::is_convertible_v<int, LookForNested>, "Can't initialize with int");

documentation for std::is_convertible建议通过查看是否可以编写一个返回 int 并具有返回类型 LookForNested 的函数来完成检查。只是为了确认你确实不能这样做,我编写了这个函数。正如预期的那样,它无法编译。

/* Attempt to initialize a LookForNested with an int; this fails. */
LookForNested returnAnInt() {
return 137;
}

我现在很困惑,因为

  • std::is_convertible_v 特性表明您确实可以使用 int 初始化 LookForNested,但是
  • 事实上,您不能将 int 转换为 LookForNested

(顺便说一下,我使用的是 g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0。)

我的问题如下:

  1. 造成这种差异的原因是什么?
  2. 如果我想测试 int 是否真的可以转换为 LookForNested,我应该使用什么来代替 std: :is_convertible_v?

谢谢!

最佳答案

  1. 正如 Kerrek SB 和 chris 在评论中提到的,std::is_convertible 只考虑构造函数的声明,而不是它的定义 - 它不执行模板实例化,因此存在差异。

  2. 您仍然可以使用 std::is_convertible,但必须更改 LookForNested 的构造函数以显示其对 T 的依赖性::NestedType 在其声明中。

您可以检查它是否存在:

template <typename T, typename T::NestedType* = nullptr>
LookForNested(const T&);

或者执行更精细的检查,比如它是否是默认构造的:

template <typename T, std::enable_if_t<std::is_default_constructible_v<typename T::NestedType>>* = nullptr>
LookForNested(const T&);

完整示例(https://gcc.godbolt.org/z/FT_eaX):

#include <type_traits>

struct LookForNested {
/* Look inside the argument type for a nested type. This won't
* compile if you invoke the constructor on a type that doesn't have
* a nested type with name NestedType.
*/
template <typename T, std::enable_if_t<std::is_default_constructible_v<typename T::NestedType>>* = nullptr>
LookForNested(const T&) {
typename T::NestedType x;
}
};

struct Good {
using NestedType = double;
};

struct Bad {};

static_assert(!std::is_convertible_v<int, LookForNested>, "Can't initialize with int");
static_assert(std::is_convertible_v<Good, LookForNested>, "Can initialize with struct which has NestedType");
static_assert(!std::is_convertible_v<Bad, LookForNested>, "Can't initialize with struct which does not have NestedType");

关于c++ - 为什么 std::is_convertible_v 返回 true 即使此转换不合法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57548458/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com