我不明白为什么第一个(好)代码可以编译,但是第二个却不能
我已经阅读了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");
}
非常感谢您!
答案 0 :(得分:2)
std::enable_if_t<std::is_arithmetic<As>::value, As>
替换As
并假定条件为真。发出错误的原因是因为您不能具有浮点类型的非类型模板参数。在这种情况下,除了SFINAE之外,您出于某种原因似乎都没有使用template参数,因此您可以将第二个As
替换为int
并进行编译。
std::enable_if_t<std::is_arithmetic<As>::value, int> = 0
答案 1 :(得分: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
}
答案 2 :(得分:-1)
您忘记了一个星号,并且不需要typename
:
template <typename As, /*typename*/ std::enable_if_t<
std::is_arithmetic<As>::value, As>* = 0 >
// here ^