std :: enable_if的两个版本之间有什么区别

问题描述 投票:2回答:3

我不明白为什么代码的第一个(好)版本编译,但第二个不编译

我读过thisthisthis,当然还有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");
}

非常感谢你!

c++ c++11 templates c++14
3个回答
2
投票

假设情况属实,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

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
}

-1
投票

你忘记了一个星号,并有一个不需要的typename

template <typename As, /*typename*/ std::enable_if_t<
std::is_arithmetic<As>::value, As>* = 0   > 
                         // here  ^
© www.soinside.com 2019 - 2024. All rights reserved.