我不明白为什么代码的第一个(好)版本编译,但第二个不编译
我读过this,this,this,当然还有this,但我仍然不明白为什么它会编译一个版本,而另一个版本却没有。如果有人可以解释它(就像总傻瓜一样),我真的很感激。
好的版本
template <typename As, typename std::enable_if<
std::is_arithmetic<As>::value, As>::type* = nullptr >
As getStringAs(const std::string& arg_name)
{
std::istringstream istr(arg_name);
As val;
istr >> val;
if (istr.fail())
throw std::invalid_argument(arg_name);
return val;
}
不好的版本
template <typename As, typename std::enable_if_t<
std::is_arithmetic<As>::value, As> = 0 >
As getStringAs(const std::string& arg_name)
{
std::istringstream istr(arg_name);
As val;
istr >> val;
if (istr.fail())
throw std::invalid_argument(arg_name);
return val;
}
预期用途:
int main()
{
return getStringAs<float>("2.f");
}
非常感谢你!
假设情况属实,std::enable_if_t<std::is_arithmetic<As>::value, As>
代替As
。发出错误的原因是您不能拥有浮点类型的非类型模板参数。在这种情况下,除了SFINAE之外你似乎没有出于任何原因使用模板参数,所以你可以用As
替换第二个int
,它应该编译。
std::enable_if_t<std::is_arithmetic<As>::value, int> = 0
std::enable_if
是一个类型,我可以用它声明变量:
std::enable_if<true, int> myVar;
你也可以这样写:
std::enable_if<true, int> myVar2{};
std::enable_if<true, int> myVar3 = {};
它没有带整数的构造函数,因此无法编译:
//Error - no way to convert 0 to std::enable_if<true, int>
std::enable_if<true, int> myVar = 0;
// Error - no way to convert nullptr to std::enable_if<true, int>
std::enable_if<true, int> myVar = nullptr;
以同样的方式,typename std::enable_if<true, int>::type*
是一个指针(特别是int*
)。它可以被赋值为0,也可以分配给nullptr
:
// This works, because you can assign 0 to a pointer
typename std::enable_if<true, int>::type* myPtr = 0;
// This works, because you can assign nullptr to a pointer
typename std::enable_if<true, int>::type* myPtr = nullptr;
enable_if
如何运作。 enable_if
是建立在hack上的,在某些情况下,如果编译器无法编译,编译器将忽略模板化函数的实例。 (注意:如果声明编译,但正文没有,编译器不能忽略)。
假设我们有两个版本的函数,你想根据某些条件在它们之间切换:
// This version gets called if T::value is true, because it'll fail to compile otherwise
template<class T, typename std::enable_if<T::value>::type* = nullptr>
void foo(){
std::cout << "T::value is true\n";
}
// This version gets called if T::value is false, because it'll fail to compile otherwise
template<class T, typename std::enable_if<not T::value>::type* = nullptr>
void foo(){
std::cout << "T::value is false\n";
}
如果你有两个类,都有一个constexpr value
成员,它将调用该函数的正确版本:
class A{
public:
constexpr static bool value = true;
};
class B {
public:
constexpr static bool value = false;
};
int main() {
foo<A>(); // Prints T::value is true
foo<B>(); // Prints T::value is false
}
你忘记了一个星号,并有一个不需要的typename
:
template <typename As, /*typename*/ std::enable_if_t<
std::is_arithmetic<As>::value, As>* = 0 >
// here ^