static_assert<std::is_floating_point<T>::value, " " ) 由于未使用的模板类型而失败



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

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

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

当我注释掉所有整型类型时,它工作正常,但我不能这样做,因为我需要能够使用T类型制作Matrix<T>实例。我将如何解决它?

请注意,我已经为每个积分/浮点类型提供了template class Matrix<T>,因为我得到了undefined reference错误。因此,我将初始化限制为积分浮点类型。

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

您有以下几种选择:

  • 在标头而不是 cpp 中提供(模板(代码(请参阅为什么只能使用标头文件中实现的模板(
  • 显式实例化方法而不是类:

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

当我注释掉所有整数类型s 时,它工作正常,但我不能这样做 这是因为我需要能够使用 T 创建一个Matrix<T>实例是一个 积分典型值E.我将如何解决它?

正如@Jarod42注释中指出的那样,当且仅当模板类型为浮点时,您可以应用 SFINAE 来限制rand()函数的使用。

额外备注:同样的技术可以应用于限制类Matrix<T>的实例化,方法是有条件地实例化特征中提到的允许类型。

下面是一个示例代码(使用 c++17 编译(来演示这个想法。

(见在线(

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

最新更新