【问题标题】:static_assert<std::is_floating_point<T>::value, "") fails because of unused template typesstatic_assert<std::is_floating_point<T>::value, "") 由于未使用的模板类型而失败
【发布时间】:2019-10-29 13:31:30
【问题描述】:

我正在制作一个模板化的Matrix 类,并且我将模板参数限制为 integralfloating 点数据类型

template class Matrix<int>;
template class Matrix<float>; ..etc

我正在实现一个random() 静态成员函数,为了使其从0.01.0 均匀随机分布,我使用std::is_floating_point&lt;T&gt; 来限制浮动 模板的使用> 点类型。我认为如果只有T 不是浮点类型,static_assert 就会触发,但是对于每个template class Matrix&lt;T&gt;;,其中 T 是 integral 类型的断言都会失败。

当我注释掉所有 integral 类型时,它工作正常,但我不能这样做,因为我需要能够使 Matrix&lt;T&gt; 实例与 T 是一个 整型。我该如何解决?

请注意,我为每个 integral/floating 点类型提供了 template class Matrix&lt;T&gt;,因为我收到了 undefined reference 错误。所以我将初始化限制为 integralfloating 点类型。

// Matrix.cpp
template<typename T>
Matrix<T> Matrix<T>::rand(const size_t& r, const size_t& c) {
    Matrix<T> result{ r, c };
    static_assert(std::is_floating_point<T>::value,
        "result_type must be a floating point type");
    const float range_from = 0.0;
    const float range_to = 1.0;
    std::random_device                  rand_dev;
    std::mt19937                        generator(rand_dev());
    std::uniform_real_distribution<T>   distr(range_from, range_to);
    for (int i = 0; i < r; i++) {
        for (int j = 0; j < c; j++) {
            result[i][j] = distr(generator);
        }
    }
    return result;
}
//...
template class Matrix<int>;
template class Matrix<long>;
template class Matrix<float>;
template class Matrix<double>;

【问题讨论】:

  • 如果显式实例化类(以及它的所有(非模板)方法),则需要 SFINAE(或 C++20 的 requires)或专业化

标签: c++ class c++11 templates typetraits


【解决方案1】:

您有多种选择:

  • 在标头而不是 cpp 中提供(模板)代码(参见 why-can-templates-only-be-implemented-in-the-header-file
  • 显式实例化方法而不是类:

    // all individual available methods of the class
    template Matrix<int> Matrix<int>::other_method(/*..*/); 
    // ...
    
    // Whole class
    template class Matrix<float>;
    template class Matrix<double>;
    
  • 使用 SFINAE:

    template<typename T>
    class Matrix
    {
        template <typename U = T,
                  std::enable_if_t<std::is_same<T, U>::value
                                   && std::is_floating_point<U>::value, int> = 0>
        Matrix<T> rand(const size_t &r, const size_t &c);
    // ...
    };
    
  • 或来自 C++20 的 requires

    template<typename T>
    class Matrix
    {
        Matrix<T> rand(const size_t &r, const size_t &c) requires (std::is_floating_point<T>::value);
    // ...
    };
    
  • 或专业化课程

    template<typename T, typename Enabler = void>
    class Matrix
    {
    // ...
    };
    
    template<typename T>
    class Matrix<T, std::enable_if_t<std::is_floating_point<T>::value>>
    {
        Matrix<T> rand(const size_t &r, const size_t &c);
    // ...
    };
    

【讨论】:

    【解决方案2】:

    当我注释掉所有 integral 类型时,它工作正常,但我做不到 这是因为我需要能够使用T 制作Matrix&lt;T&gt; 实例是一个 整体式e。我该如何解决?

    正如 @Jarod42 在 cmets 中指出的那样,当且仅当模板类型为一个浮点数。

    额外说明:可以应用相同的技术来限制类 Matrix&lt;T&gt; 的实例化,方法是针对特征中提到的允许类型有条件地实例化类。

    以下是一个示例代码(使用 编译),它演示了这个想法。

    (See online)

    #include <iostream>
    #include <type_traits> // for std::conjunction, std::negation, std::is_arithmetic, std::is_floating_point, std::enable_if
    
    // traits for filtering out the allowed types
    template<typename Type>
    using is_allowed = std::conjunction<
        std::is_arithmetic<Type>,    // is equal to  std::is_integral_v<T> || std::is_floating_point_v<T>>
        std::negation<std::is_same<Type, bool>>,    // negate the types which shouldn't be compiled
        std::negation<std::is_same<Type, char>>,
        std::negation<std::is_same<Type, char16_t>>,
        std::negation<std::is_same<Type, char32_t>>,
        std::negation<std::is_same<Type, wchar_t>>
    >;
    
    template<typename Type, typename ReType = void>
    using is_allowed_type = std::enable_if_t<is_allowed<Type>::value, ReType>;
    
    template<typename Type, typename Enable = void> class Matrix;
    // conditional instantiation of the template class
    template<typename Type> class Matrix<Type, is_allowed_type<Type>> /* final */
    {
    public:
        template<typename T = Type>
        std::enable_if_t<std::is_floating_point_v<T>, Matrix<T>> rand(const size_t& r, const size_t& c)
       //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SFINAE to restrict the use of rand()
        {
            Matrix<T> result{/*args*/};
            // other code
            return result;
        }
    };
    template class Matrix<int>;
    template class Matrix<long>;
    template class Matrix<float>;
    
    int main()
    {
       Matrix<double> obj;
       obj.rand(1, 2);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-19
      • 2021-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多