似乎使用带有SFINAE enable_if的decltype并不简单.我尝试用三种不同的方式使用enable_if编写go.所有这些都因编译器错误而失败(使用GCC字面意思:“错误:’事物’不是’foo’的成员”和实例化上下文).
#include <type_traits> struct foo { enum { has_thing = false }; }; struct bar { enum { has_thing = true }; static int thing() { return 0; } }; template <typename T> struct Test { /*auto go(typename std::enable_if<T::has_thing,int>::type=0) -> decltype(T::thing()) { return T::thing(); }*/ /*typename std::enable_if<T::has_thing,decltype(T::thing())>::type go() { return T::thing(); }*/ template <bool B=T::has_thing,typename std::enable_if<B,int>::type = 0> auto go() -> decltype(T::thing()) { return T::thing(); } }; int main() { Test<bar> b; Test<foo> f; }
我可以看到问题是什么 – 在enable_if甚至有机会排除该函数之前需要发生decltype.剩下的问题是如何解决并获得类似的行为?是否有一种简单,通用的方法来执行此操作而无需在enable_if中编写has_thing trait?
使用G 4.7和clang 3.0进行测试.
解决方法
如果go方法是模板方法,则SFINAE将起作用:
template <typename T> struct Test { template <class U = T> auto go() -> decltype(U::thing()) { return T::thing(); } };
你也可以使用has_thing值,但是没有必要这样做,因为SFINAE将在上面的例子中处理它:
template <class U = T,typename std::enable_if<U::has_thing,int>::type = 0> auto go() -> decltype(U::thing()) { return T::thing(); }
然后:
int main() { Test<bar> b; Test<foo> f; b.go(); // Works! f.go(); // Fails! }