我试图通过一个简单的示例来了解如何使用std::enable_if.在我阅读了这个答案之后,我认为想出一个简单的例子应该不会太难。我想用来std::enable_if在两个成员函数之间进行选择,并且只允许使用其中一个。
std::enable_if
不幸的是,以下内容无法使用 gcc 4.7 编译,经过数小时的尝试,我问你们我的错误是什么。
#include <utility> #include <iostream> template< class T > class Y { public: template < typename = typename std::enable_if< true >::type > T foo() { return 10; } template < typename = typename std::enable_if< false >::type > T foo() { return 10; } }; int main() { Y< double > y; std::cout << y.foo() << std::endl; }
gcc 报告以下问题:
% LANG=C make CXXFLAGS="-std=c++0x" enable_if g++ -std=c++0x enable_if.cpp -o enable_if enable_if.cpp:12:65: error: `type' in `struct std::enable_if<false>' does not name a type enable_if.cpp:13:15: error: `template<class T> template<class> T Y::foo()' cannot be overloaded enable_if.cpp:9:15: error: with `template<class T> template<class> T Y::foo()'
为什么 g++ 不删除第二个成员函数的错误实例化?根据标准,`std::enable_if< bool, T = void
::type`只有当布尔模板参数为真时才存在。但是为什么 g 不认为这是 SFINAE 呢?我认为重载错误信息来自g没有删除第二个成员函数的问题,认为这应该是一个重载。
SFINAE 仅在模板参数的参数推导中的替换使构造格式错误时才有效。没有这样的替代品。
我也想到了这一点并尝试使用std::is_same< T, int >::value并`! std::is_same< T, int ::value`给出相同的结果。
我也想到了这一点并尝试使用std::is_same< T, int >::value并`! std::is_same< T, int
std::is_same< T, int >::value
::value`给出相同的结果。
这是因为当类模板被实例化时(在其他情况下创建类型对象时会发生这种Y<int>情况),它会实例化其所有成员声明(不一定是它们的定义/主体!)。其中还有它的成员模板。请注意,这T是已知的,并且!std::is_same< T, int >::value产生错误。所以它将创建一个Y<int>包含
Y<int>
T
!std::is_same< T, int >::value
class Y<int> { public: /* instantiated from template < typename = typename std::enable_if< std::is_same< T, int >::value >::type > T foo() { return 10; } */ template < typename = typename std::enable_if< true >::type > int foo(); /* instantiated from template < typename = typename std::enable_if< ! std::is_same< T, int >::value >::type > T foo() { return 10; } */ template < typename = typename std::enable_if< false >::type > int foo(); };
访问不存在的std::enable_if<false>::type类型,因此该声明格式不正确。因此您的程序无效。
std::enable_if<false>::type
您需要使成员模板enable_if依赖于成员模板本身的参数。那么声明是有效的,因为整个类型仍然是依赖的。当您尝试调用其中一个时,会发生对其模板参数的参数推导,并且 SFINAE 会按预期发生。
enable_if