我一直在尝试将 SFINAE 应用于此处描述的“has_member”类型的结构。
所以我试图利用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 enum是否正常工作。
第二行输出的结果的结构体Constrexr"has_enum_name::值"。我只是尝试使用d::enable_if结合d::is_enum使解密类型返回一些东西……在这种情况下,std::true_type()。如你所见,输出返回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应该返回true,这意味着enable_if应该返回true_type,而Dectype应该返回true_type()。
下一个输出只是检查是否d::is_enum
下一个输出只是“has_enum_name”结构的副本,但是我替换了is_enum
因此,由于某种原因,is_enum似乎无法返回true。知道我在这里做错了什么吗?
当你遇到这样的问题时,让编译器帮助你。删除(…)
重载以强制编译错误,看看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
这正是问题所在:您只是忘记添加类型名称
。如果类型是非类型
,则 T::type()
可能有效:它可能只是一个函数调用。这就是编译器解析它的方式。
顺便说一下,< code > decltype(typename T::type())似乎没有什么意义,除非您特别想检查该类型是否是默认可构造的,而这不是您在这里要做的。您可以直接使用< code>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;
如果您在没有< code>typename的情况下尝试这样做,您会立即得到一条有用的错误消息。
你的值
初始化也是不必要的复杂,因为你已经知道你正在处理false_type
或true_type
:两者都有一个你可以使用的价值
成员。
static constexpr bool value = decltype(test<T>(0))::value;