c++ - enable_if 使用 constexpr bool 测试不起作用

标签 c++ c++11 templates constexpr enable-if

我有一个数学函数,我希望它能够接受 double 或 double 的数组/vector/容器,并且其行为略有不同。

我正在尝试使用 SFINAE 和类型特征来选择正确的函数。

这是一个最小的例子:

#include <iostream>
#include <vector>
#include <type_traits>

template <typename T>
constexpr bool Iscontainer()
{
    if constexpr (std::is_class<T>::value && std::is_arithmetic<typename T::value_type>::value) {
        return true;
    }
    return false;
}

// Function 1 (double):
template <typename T>
typename std::enable_if<std::is_arithmetic<T>::value>::type g(T const & t)
{
    std::cout << "this is for a double" << t << std::endl;
}

// Function 2 (vec), version 1:
template <typename T>
typename std::enable_if<IsContainer<T>()>::type g(T const & t)
{
    std::cout << "this is for a container" << t[0] << std::endl;
}

int main()
{
    std::vector<double> v {1, 2};
    std::array<double, 2> a {1, 2};
    double d {0.1};

    g<>(v);
    g<>(a);
    g<>(d);  // error here
}

我得到一个编译时错误:

../main.cpp:8:47: error: ‘double’ is not a class, struct, or union type
     if constexpr (std::is_class<T>::value && std::is_arithmetic<typename     T::value_type>::value) {
                   ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~

但是,当我将函数 2 替换为:

// Function 2 (vec), version 2:
template <typename T>
typename std::enable_if<std::is_class<T>::value && std::is_arithmetic<typename T::value_type>::value>::type
g(T const & t)
{
    std::cout << "this is for a vector" << t[0] << std::endl;
}

有效。

我的问题是我不明白为什么第一个版本不起作用.. 而且我更喜欢第一个版本的可读性。

最佳答案

失败的原因很简单。您不调用 SFINAE,当编译器尝试计算它看到的表达式时:

if constexpr (std::is_class<double>::value // this is fine it's false
   && std::is_arithmetic<typename double::value_type>::value // problem here!
)

整个语句被评估,if 没有短路。与您目前所拥有的最接近的解决方案是显式拆分 if,以便在 T 不是类并且第二次检查无意义时丢弃有问题的部分。

#include <iostream>
#include <vector>
#include <type_traits>

template <typename T>
constexpr bool IsVector()
{
    if constexpr (std::is_class<T>::value) {
        if constexpr (std::is_arithmetic<typename T::value_type>::value) {
            return true;
        }
    }
    return false;
}

// Function 1 (double):
template <typename T>
typename std::enable_if<std::is_arithmetic<T>::value>::type g(T const & t)
{
    std::cout << "this is for a double" << t << std::endl;
}

// Function 2 (vec), version 1:
template <typename T>
typename std::enable_if<IsVector<T>()>::type g(T const & t)
{
    std::cout << "this is for a vector" << t[0] << std::endl;
}

int main()
{
    std::vector<double> v {1, 2};
    double d {0.1};

    g<>(v);
    g<>(d);  // error here
}

或者,我建议使用 using 别名:

template <typename T>
using IsVector2 = std::conjunction<typename std::is_class<T>, std::is_arithmetic<typename T::value_type> >;

template <typename T>
typename std::enable_if<IsVector2<T>::value>::type g(T const & t)
{
    std::cout << "this is for a vector" << t[0] << std::endl;
}

您还可以更好地命名它。它并不真正检查 Tvector 还是容器(在您编辑之后)。您当前的定义也有点松散。

关于c++ - enable_if 使用 constexpr bool 测试不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51432244/

相关文章:

c++ - 运算符重载使用 * 和 *= 作为点积或叉积

c++ - C++ 中的引用语义

c++ - GCC 6.2.0 的 CXX11 undefined reference

c++ - std::bind 不工作

c++ - 如何编写一个通用的 "getData"函数?

c++ - 模板化类内部函数的模板特化

c++ - 由于继承而返回拷贝的堆栈?

c++ - 如何使用 C++ 在类中定义函数?

c++ - 基于运算符推导模板返回类型? : result

string - 转到模板 : range over string