enable_if使用constexpr bool测试不起作用 [英] enable_if using a constexpr bool test not working

查看:96
本文介绍了enable_if使用constexpr bool测试不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个数学函数,希望能够接受双精度数或双精度数的数组/向量/容器,并且行为略有不同。

I have a maths function that I want to be able to accept either a double, or a array/vector/container of doubles, and behave slightly differently.

我正在尝试使用SFINAE并键入traits选择正确的函数。

I am attempting to use SFINAE and type traits to select the correct function.

这里是一个最小的示例:

Here is a minimal example:

#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
}

我得到一个编译时错误:

I get a compile time error:

../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具有:

However, when I replace function 2 with:

// 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;
}

有效。

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

My problem is I don't understand why the first version does not work.. And I prefer the readability of the first version.

推荐答案

失败的原因很简单。您没有调用SFINAE,并且当编译器尝试评估表达式时,它会看到:

The reason why it fails is simple. You do not invoke SFINAE, and when the compiler tries to evaluate the expressions it sees:

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 时丢弃有问题的部分

The whole statement is evaluated, there is no short-circuit for the if. The closest solution to what you currently have is to explicitly split the if, so that the problematic part is discarded when T is not a class and the second check is nonsensical.

#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
}

或者我建议使用别名:

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;
}

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

You could also name it better. It doesn't really check whether T is a vector, or a container (after your edit). Your current definition is a bit loose as well.

这篇关于enable_if使用constexpr bool测试不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆