以下 has_member 函数无法正常使用 SFINAE 是什么?
What does SFINAE not work correctly with following has_member function?
我正在尝试 Walter Brown's TMP talk 中的示例,并且我正在尝试让他的 has_member
实现正常工作。
然而,该实现似乎错误地 return 正确,这让我相信我不理解 SFINAE 的一些细节。
#include <iostream>
#include <type_traits>
template <class ...>
using void_t = void;
template <class, class = void>
struct has_type_member: std::false_type {};
template <class T>
struct has_type_member<T, void_t<typename T::type> >: std::true_type {};
struct FooWithType
{
typedef int type;
};
struct FooNoType
{
};
int main()
{
std::cout << "Does FooWithType have type member? " <<
(has_type_member<FooWithType>() ? "YES" : "NO") << "\n";
std::cout << "Does FooNoType have type member? " <<
(has_type_member<FooNoType>() ? "YES" : "NO") << "\n";
return 1;
}
输出为:
Does FooWithType have type member? YES
Does FooNoType have type member? YES
我在 Ubuntu 上使用 gcc 4.8.2。
问题是 gcc 4.8.2(和 gcc 5.0 之前的版本)不认为别名模板中未使用的参数适用于 SFINAE。解决方法是转发到 voider
class 模板:
template <class ... T> struct voider { using type = void; };
template <class ... T>
using void_t = typename voider<T...>::type;
来自 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3911.pdf 第 2.3 节:
Alas, we have encountered implementation divergence (Clang vs. GCC) while working with the
above very simple definition. We (continue to) conjecture that this is because of CWG issue 1558:
“The treatment of unused arguments in an alias template specialization is not specified by the
current wording of 14.5.7 [temp.alias].”
我正在尝试 Walter Brown's TMP talk 中的示例,并且我正在尝试让他的 has_member
实现正常工作。
然而,该实现似乎错误地 return 正确,这让我相信我不理解 SFINAE 的一些细节。
#include <iostream>
#include <type_traits>
template <class ...>
using void_t = void;
template <class, class = void>
struct has_type_member: std::false_type {};
template <class T>
struct has_type_member<T, void_t<typename T::type> >: std::true_type {};
struct FooWithType
{
typedef int type;
};
struct FooNoType
{
};
int main()
{
std::cout << "Does FooWithType have type member? " <<
(has_type_member<FooWithType>() ? "YES" : "NO") << "\n";
std::cout << "Does FooNoType have type member? " <<
(has_type_member<FooNoType>() ? "YES" : "NO") << "\n";
return 1;
}
输出为:
Does FooWithType have type member? YES
Does FooNoType have type member? YES
我在 Ubuntu 上使用 gcc 4.8.2。
问题是 gcc 4.8.2(和 gcc 5.0 之前的版本)不认为别名模板中未使用的参数适用于 SFINAE。解决方法是转发到 voider
class 模板:
template <class ... T> struct voider { using type = void; };
template <class ... T>
using void_t = typename voider<T...>::type;
来自 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3911.pdf 第 2.3 节:
Alas, we have encountered implementation divergence (Clang vs. GCC) while working with the above very simple definition. We (continue to) conjecture that this is because of CWG issue 1558: “The treatment of unused arguments in an alias template specialization is not specified by the current wording of 14.5.7 [temp.alias].”