is_enum 导致 SFINAE 应用程序出现错误行为?
is_enum causing incorrect behavior for SFINAE application?
我一直在尝试将 SFINAE 应用于 "has_member" 类型的结构,如 here 所述。
所以我试图使用 c++11 的一些特性来简化这些解决方案。在检查枚举是否存在时遇到一些问题,但我似乎无法在此处找到我的逻辑错误。代码是:
#include<iostream>
template<typename T >
struct has_enum_name
{
private:
// ***** this is the line that isn't working *****
// If U has an enum "name", then I expect is_enum to return true…
// Then I expect enable_if<>::type to be std::true_type…etc. This isn't what happens.
template<typename U> static auto test(int) -> decltype(
std::enable_if<std::is_enum< typename U::name >::value, std::true_type>::type() );
template<typename U> static auto test(...) -> std::false_type;
public:
static constexpr bool value =
!(std::is_same<decltype(test<T>(0)),std::false_type>::value);
static constexpr bool is_enum()
{
return std::is_enum<typename T::name>::value;
}
};
template<typename T >
struct has_enum_name_2
{
private:
template<typename U> static auto test(int) -> decltype(
std::enable_if<true, std::true_type>::type() );
template<typename U> static auto test(...) -> std::false_type;
public:
static constexpr bool value =
!(std::is_same<decltype(test<T>(0)),std::false_type>::value);
};
struct Foo
{
enum class name
{
enum1,
enum2
};
};
int main()
{
std::cout<<"std::is_enum<Foo::name>::value = "<<std::is_enum<Foo::name>::value<<std::endl;
std::cout<<"has_enum_name<Foo>::value = "<<has_enum_name<Foo>::value<<std::endl;
std::cout<<"has_enum_name<Foo>::is_enum() = "<<has_enum_name<Foo>::is_enum()<<std::endl;
std::cout<<"has_enum_name_2<Foo>::value = "<<has_enum_name_2<Foo>::value<<std::endl;
}
运行 使用 gcc 4.9.2 给出
$ ./a.out
std::is_enum<Foo::name>::value = 1
has_enum_name<Foo>::value = 0
has_enum_name<Foo>::is_enum() = 1
has_enum_name_2<Foo>::value = 1
第一行输出验证 std::is_enum 对于 Foo::name 枚举是否正确工作。
第二行输出struct constexpr的结果"has_enum_name::value"。我只是想将 std::enable_if 与 std::is_enum 结合使用,使 decltype return 成为某种东西……在本例中为 std::true_type()。如您所见,输出 returns false...所以行:
template<typename U> static auto test(int) -> decltype(
std::enable_if<std::is_enum< typename U::name >::value, std::true_type>::type() );
没有像我认为的那样锻炼。我认为 is_enum 应该 return 为真,也就是说 enable_if 应该 return true_type,decltype 应该 return true_type( ).
下一个输出只是检查 std::is_enum<> 是否在结构中正常工作……是的。
下一个输出只是 "has_enum_name" 结构的一个副本,但我用硬编码 "true" 替换了可疑行中的 is_enum<> ......并且它工作正常。
因此,出于某种原因,is_enum 似乎无法正常工作 return。知道我在这里做错了什么吗?
当你遇到这样的问题,就让编译器来帮你吧。删除 (...)
重载以强制编译错误,看看 GCC 告诉你什么:
test.cc: In instantiation of ‘constexpr const bool has_enum_name<Foo>::value’:
test.cc:51:71: required from here
test.cc:18:33: error: no matching function for call to ‘has_enum_name<Foo>::test(int)’
!(std::is_same<decltype(test<T>(0)),std::false_type>::value);
^
test.cc:18:33: note: candidate is:
test.cc:12:36: note: template<class U> static decltype (std::enable_if<std::is_enum<typename U::name>::value, std::integral_constant<bool, true> >::type()) has_enum_name<T>::test(int) [with U = U; T = Foo]
template<typename U> static auto test(int) -> decltype(
^
test.cc:12:36: note: template argument deduction/substitution failed:
test.cc: In substitution of ‘template<class U> static decltype (std::enable_if<std::is_enum<typename U::name>::value, std::integral_constant<bool, true> >::type()) has_enum_name<T>::test(int) [with U = Foo]’:
test.cc:18:33: required from ‘constexpr const bool has_enum_name<Foo>::value’
test.cc:51:71: required from here
test.cc:13:83: error: dependent-name ‘std::enable_if<std::is_enum<typename T::name>::value, std::integral_constant<bool, true> >::type’ is parsed as a non-type, but instantiation yields a type
std::enable_if<std::is_enum< typename U::name >::value, std::true_type>::type() );
^
test.cc:13:83: note: say ‘typename std::enable_if<std::is_enum<typename T::name>::value, std::integral_constant<bool, true> >::type’ if a type is meant
这正是问题所在:您只是忘记添加 typename
。如果 type
是非类型,T::type()
可能有效:它可能只是一个函数调用。这就是编译器解析它的方式。
顺便说一句,decltype(typename T::type())
似乎有点毫无意义,除非您专门尝试检查该类型是否可默认构造,而这不是您要在此处进行的。您可以直接使用 typename T::type
,像这样:
template<typename U> static auto test(int) ->
typename std::enable_if<std::is_enum<typename U::name>::value, std::true_type>::type;
如果您在没有 typename
的情况下尝试过,您会立即收到一条有用的错误消息。
你对 value
的初始化也不必要地复杂,因为你已经知道你正在处理 false_type
或 true_type
:它们都有一个 value
成员你可以使用。
static constexpr bool value = decltype(test<T>(0))::value;
我一直在尝试将 SFINAE 应用于 "has_member" 类型的结构,如 here 所述。
所以我试图使用 c++11 的一些特性来简化这些解决方案。在检查枚举是否存在时遇到一些问题,但我似乎无法在此处找到我的逻辑错误。代码是:
#include<iostream>
template<typename T >
struct has_enum_name
{
private:
// ***** this is the line that isn't working *****
// If U has an enum "name", then I expect is_enum to return true…
// Then I expect enable_if<>::type to be std::true_type…etc. This isn't what happens.
template<typename U> static auto test(int) -> decltype(
std::enable_if<std::is_enum< typename U::name >::value, std::true_type>::type() );
template<typename U> static auto test(...) -> std::false_type;
public:
static constexpr bool value =
!(std::is_same<decltype(test<T>(0)),std::false_type>::value);
static constexpr bool is_enum()
{
return std::is_enum<typename T::name>::value;
}
};
template<typename T >
struct has_enum_name_2
{
private:
template<typename U> static auto test(int) -> decltype(
std::enable_if<true, std::true_type>::type() );
template<typename U> static auto test(...) -> std::false_type;
public:
static constexpr bool value =
!(std::is_same<decltype(test<T>(0)),std::false_type>::value);
};
struct Foo
{
enum class name
{
enum1,
enum2
};
};
int main()
{
std::cout<<"std::is_enum<Foo::name>::value = "<<std::is_enum<Foo::name>::value<<std::endl;
std::cout<<"has_enum_name<Foo>::value = "<<has_enum_name<Foo>::value<<std::endl;
std::cout<<"has_enum_name<Foo>::is_enum() = "<<has_enum_name<Foo>::is_enum()<<std::endl;
std::cout<<"has_enum_name_2<Foo>::value = "<<has_enum_name_2<Foo>::value<<std::endl;
}
运行 使用 gcc 4.9.2 给出
$ ./a.out
std::is_enum<Foo::name>::value = 1
has_enum_name<Foo>::value = 0
has_enum_name<Foo>::is_enum() = 1
has_enum_name_2<Foo>::value = 1
第一行输出验证 std::is_enum 对于 Foo::name 枚举是否正确工作。
第二行输出struct constexpr的结果"has_enum_name::value"。我只是想将 std::enable_if 与 std::is_enum 结合使用,使 decltype return 成为某种东西……在本例中为 std::true_type()。如您所见,输出 returns false...所以行:
template<typename U> static auto test(int) -> decltype(
std::enable_if<std::is_enum< typename U::name >::value, std::true_type>::type() );
没有像我认为的那样锻炼。我认为 is_enum 应该 return 为真,也就是说 enable_if 应该 return true_type,decltype 应该 return true_type( ).
下一个输出只是检查 std::is_enum<> 是否在结构中正常工作……是的。
下一个输出只是 "has_enum_name" 结构的一个副本,但我用硬编码 "true" 替换了可疑行中的 is_enum<> ......并且它工作正常。
因此,出于某种原因,is_enum 似乎无法正常工作 return。知道我在这里做错了什么吗?
当你遇到这样的问题,就让编译器来帮你吧。删除 (...)
重载以强制编译错误,看看 GCC 告诉你什么:
test.cc: In instantiation of ‘constexpr const bool has_enum_name<Foo>::value’:
test.cc:51:71: required from here
test.cc:18:33: error: no matching function for call to ‘has_enum_name<Foo>::test(int)’
!(std::is_same<decltype(test<T>(0)),std::false_type>::value);
^
test.cc:18:33: note: candidate is:
test.cc:12:36: note: template<class U> static decltype (std::enable_if<std::is_enum<typename U::name>::value, std::integral_constant<bool, true> >::type()) has_enum_name<T>::test(int) [with U = U; T = Foo]
template<typename U> static auto test(int) -> decltype(
^
test.cc:12:36: note: template argument deduction/substitution failed:
test.cc: In substitution of ‘template<class U> static decltype (std::enable_if<std::is_enum<typename U::name>::value, std::integral_constant<bool, true> >::type()) has_enum_name<T>::test(int) [with U = Foo]’:
test.cc:18:33: required from ‘constexpr const bool has_enum_name<Foo>::value’
test.cc:51:71: required from here
test.cc:13:83: error: dependent-name ‘std::enable_if<std::is_enum<typename T::name>::value, std::integral_constant<bool, true> >::type’ is parsed as a non-type, but instantiation yields a type
std::enable_if<std::is_enum< typename U::name >::value, std::true_type>::type() );
^
test.cc:13:83: note: say ‘typename std::enable_if<std::is_enum<typename T::name>::value, std::integral_constant<bool, true> >::type’ if a type is meant
这正是问题所在:您只是忘记添加 typename
。如果 type
是非类型,T::type()
可能有效:它可能只是一个函数调用。这就是编译器解析它的方式。
顺便说一句,decltype(typename T::type())
似乎有点毫无意义,除非您专门尝试检查该类型是否可默认构造,而这不是您要在此处进行的。您可以直接使用 typename T::type
,像这样:
template<typename U> static auto test(int) ->
typename std::enable_if<std::is_enum<typename U::name>::value, std::true_type>::type;
如果您在没有 typename
的情况下尝试过,您会立即收到一条有用的错误消息。
你对 value
的初始化也不必要地复杂,因为你已经知道你正在处理 false_type
或 true_type
:它们都有一个 value
成员你可以使用。
static constexpr bool value = decltype(test<T>(0))::value;