我正在研究一个C ++项目,该项目需要使用类型自省来确定模板是哪种对象类型。这样,我遇到了一个不寻常的问题。我已将根本问题隔离为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
特性表明您确实可以使用LookForNested
初始化int
,但是int
转换为LookForNested
。(顺便说一下,我正在使用g ++(Ubuntu 7.4.0-1ubuntu1〜18.04.1)7.4.0。)
我的问题如下:
int
是否真的可以转换为LookForNested
,可以代替std::is_convertible_v
使用什么?谢谢!
答案 0 :(得分:1)
正如评论中的Kerrek SB和chris所述,std::is_convertible
仅考虑构造函数的声明,而不考虑其定义-它不执行模板实例化,因此存在差异。
您仍然可以使用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");