为一组类型专门化多个模板

Specialize Many Templates for a Set of Types

本文关键字:专门化 类型 一组      更新时间:2023-10-16

如何专门化各种标量值的许多模板?(如int, float, size_t, uint32_t,以及stdint头中定义的类型)?

我可以避免为每个类型对每个模板进行专门化吗?如果可能的话,我不想使用boost或其他非标准库。

对于一组类型的模板专门化有一些解决方案:

  1. 将每个模板替换为多个函数。每个标量类型对应一个函数。(但有很多模板。

  2. 如果模板采用非标量类型,则失败。(但我也想为数组类型编写模板。这意味着我需要更改函数的名称。一组用于标量-标量计算的函数名。另一个用于标量矩阵计算的集合。又是一个矩阵-矩阵计算的集合。如果我试图重载操作符,我猜这不会工作。)

  3. Nawaz的元编程解决方案。

  4. 为每个标量类型专门化一个泛型模板。例如,写inline long getRatio<long>, inline long getRatio<float>等。可以工作,但需要为许多模板这样做

再次感谢。

的例子(这里使用了安德鲁的解决方案。改编为旧的STD库。仍然需要c++11。用Intel ICC编译-std=c++11):

#define STD_POORMAN stdpoor
namespace stdpoor{
    template<bool B, class T = void>
    struct enable_if_t {}; 
    template<class T>
    struct enable_if_t<true, T> { typedef T type; };
    template<class T, T v>
    struct integral_constant {
        static constexpr T value = v;
        typedef T value_type;
        typedef integral_constant type;
        constexpr operator value_type() const {
            noexcept return value;
        }
        constexpr value_type operator()() const {
            noexcept return value;
        }
    };
    typedef integral_constant<bool,true> true_type;
    typedef integral_constant<bool,false> false_type;
}
template <typename T>
class SimpleArray;
template <typename T>
struct is_ndscalar : STD_POORMAN::false_type {};
// Specialisations for supported scalar types:
template <> struct is_ndscalar<int> : STD_POORMAN::true_type {};
template <> struct is_ndscalar<float> : STD_POORMAN::true_type {};
template <> struct is_ndscalar<double> : STD_POORMAN::true_type {};
template <> struct is_ndscalar<long> : STD_POORMAN::true_type {};
template <> struct is_ndscalar<long long> : STD_POORMAN::true_type {};

template <typename T>
class SimpleArray{
    public:
        T* ar_data; //pointer to data
        int size; //#elements in the array
        SimpleArray(T* in_ar_data, int in_size){
            ar_data = in_ar_data;
            size = in_size;
        };
        template <typename T>
        void operator+=(const SimpleArray<T>& B){
            //array-array +=
            int i;
            for(i = 0; i < size; ++i){
                ar_data[i] += B.ar_data[i];
            }
        }
        template <typename T>
        STD_POORMAN::enable_if_t<is_ndscalar<T>::value, void>
        operator+=(const T b){
            //array-scalar +=
            int i;
            for(i = 0; i < size; ++i){
                ar_data[i] += b;
            }
        }
};
int main(void){
    int base_array[10];
    SimpleArray<int> A(base_array, 10);
    A += A;
    A += 3; 
}

将其浓缩为一个较小的示例,基于对该问题的评论中的讨论,您有一个类型Matrix<T>,并且您希望实现,例如operator+=。该操作符的行为取决于操作数是标量还是另一个矩阵。

因此,您需要提供两个专门化;一个用于矩阵-标量运算,一个用于矩阵-矩阵运算。在这些类型中,您希望接受任何有效的标量类型或任何有效的矩阵类型。

这是使用std::enable_if的类型特征和SFINAE的经典用例。定义一个trait is_scalar:

// Base template:
template <typename T>
struct is_scalar : std::false_type {};
// Specialisations for supported scalar types:
template <> struct is_scalar<int> : std::true_type {};
template <> struct is_scalar<float> : std::true_type {};
template <> struct is_scalar<double> : std::true_type {};
// etc.

和一个性状is_matrix:

// Base template:
template <typename T>
struct is_matrix : std::false_type {};
// Specialisations:
template<typename T>
struct is_matrix<Matrix<T>> : std::true_type {};
// and possibly others...

操作符将是如下形式的(成员)函数模板:

template <typename T>
std::enable_if_t<is_scalar<T>::value, Matrix&> operator+=(const T& rhs) {
  // Implementation for addition of scalar to matrix
}
template <typename T>
std::enable_if_t<is_matrix<T>::value, Matrix&> operator+=(const T& rhs) {
  // Implementation for addition of matrix to matrix
}

注意is_scalar已经由标准库提供给您了!所有这些留给您的是为您支持的任何矩阵类型定义is_matrix专门化。

如果您只想为某些类型实现此模板,您可以在.cpp文件中声明它们,类似于:为什么模板只能在头文件中实现?

如果你想在这个模板中允许任何东西,但明确声明某些类型,这个链接可能会有帮助:http://en.cppreference.com/w/cpp/language/template_specialization