SFINAE 模板的 CUDA 10.1 编译错误

jwm*_*jwm 2 cuda c++11

CUDA 10.1
g++ 7.3

为了单元测试套件的目的,我需要大量可重复的数据(超过可以硬编码的数据)。我提出了这个“生成器”范例,其想法是它可以用来向任意容器填充数据。

现在我需要扩展生成器来填充多值容器(float2int2thrust::complex)。我的解决方案是使用 SFINAE 根据是否可以从单个值构造函数或需要一对值来有条件地定义函数。

下面的代码使用 GCC ( -std=c++1z) 可以正常编译,但使用 nvcc ( -std=c++14)则失败

#include <random>
#include <type_traits>

template <typename T>
class RandomGenerator
{
public:
    RandomGenerator(T min, T max, unsigned seed = 42);

    // Generate the next element in the sequence. This requires keeping all the necessary state
    // to advance
    T operator()();

    // fill a container if it is scalar
    template<typename Container>
    typename std::enable_if_t<std::is_constructible_v<typename Container::value_type, T>>
    fill( Container& c );

    // fill a container if it takes 2 values (e.g., complex)
    template<typename Container>
    typename std::enable_if_t<std::is_constructible_v<typename Container::value_type, T, T>>
    fill2( Container& c );

protected:
private:
    std::uniform_real_distribution< T > dist;
    std::mt19937 rng;
};


// Constructor - define the domain of this generation
template <typename T>
RandomGenerator<T>::RandomGenerator(T min, T max, unsigned seed)
    : dist(min, max)
    , rng()
{
    rng.seed(seed);
}

// generate one random number
template <typename T>
T
RandomGenerator<T>::operator()()
{
    return dist(rng);
}

template <typename T>
template<typename Container>
typename std::enable_if_t<std::is_constructible_v<typename Container::value_type, T>>
RandomGenerator<T>::fill( Container& c )
{
    std::generate(c.begin(), c.end(), *this);
}

template <typename T>
template<typename Container>
typename std::enable_if_t<std::is_constructible_v<typename Container::value_type, T, T>>
RandomGenerator<T>::fill2( Container& c )
{
    std::generate(c.begin(), c.end(), [this]() { return typename Container::value_type( (*this)(), (*this)() ); });
}


Run Code Online (Sandbox Code Playgroud)

编译器错误:

/usr/local/cuda/bin/nvcc  -g -Xcompiler=-fPIE -gencode=arch=compute_60,code=sm_60 --std=c++14 --use_fast_math -Xcompiler -pthread -x cu -dc unittest.cu -o unittest.cu.o
RandomGenerator.hh(30): error: namespace "std" has no member "is_constructible_v"

RandomGenerator.hh(30): error: type name is not allowed

RandomGenerator.hh(30): error: expected an identifier

RandomGenerator.hh(34): error: namespace "std" has no member "is_constructible_v"

RandomGenerator.hh(34): error: type name is not allowed

RandomGenerator.hh(34): error: too many arguments for alias template "std::enable_if_t"

RandomGenerator.hh(34): error: expected an identifier

RandomGenerator.hh(63): error: namespace "std" has no member "is_constructible_v"

RandomGenerator.hh(63): error: type name is not allowed

RandomGenerator.hh(63): error: expected an identifier

RandomGenerator.hh(71): error: namespace "std" has no member "is_constructible_v"

RandomGenerator.hh(71): error: type name is not allowed

RandomGenerator.hh(71): error: too many arguments for alias template "std::enable_if_t"

RandomGenerator.hh(71): error: expected a ";"

Run Code Online (Sandbox Code Playgroud)

我错过了什么吗?有没有办法把这个传递给CUDA?


更新

看来具体问题在于std::enable_if_t, std::is_XXX_v。如果我使用更详细的形式而不是这些类型定义

/usr/local/cuda/bin/nvcc  -g -Xcompiler=-fPIE -gencode=arch=compute_60,code=sm_60 --std=c++14 --use_fast_math -Xcompiler -pthread -x cu -dc unittest.cu -o unittest.cu.o
RandomGenerator.hh(30): error: namespace "std" has no member "is_constructible_v"

RandomGenerator.hh(30): error: type name is not allowed

RandomGenerator.hh(30): error: expected an identifier

RandomGenerator.hh(34): error: namespace "std" has no member "is_constructible_v"

RandomGenerator.hh(34): error: type name is not allowed

RandomGenerator.hh(34): error: too many arguments for alias template "std::enable_if_t"

RandomGenerator.hh(34): error: expected an identifier

RandomGenerator.hh(63): error: namespace "std" has no member "is_constructible_v"

RandomGenerator.hh(63): error: type name is not allowed

RandomGenerator.hh(63): error: expected an identifier

RandomGenerator.hh(71): error: namespace "std" has no member "is_constructible_v"

RandomGenerator.hh(71): error: type name is not allowed

RandomGenerator.hh(71): error: too many arguments for alias template "std::enable_if_t"

RandomGenerator.hh(71): error: expected a ";"

Run Code Online (Sandbox Code Playgroud)

那么nvcc就可以处理它。

Sha*_*dow 5

编译器错误提示您它对std::is_constructible_v. 这不是因为从 gcc 切换到 nvcc,而是因为从 c++17 切换到 c++14。您已经发现可以使用::value表格来代替,这就是转到这里的方法。(当然,如果您计划在 nvcc 支持后立即将 c++17 作为项目的要求,您也可以扩展标准命名空间。)

您可以保留std::enable_if_t虽然,因为它已在 c++14 中引入。


更一般地说,我们可以发现所有std::something_t快捷方式从 c++14 开始都可用,但std::something_v快捷方式是在 c++17 中引入的。