【问题标题】:Template specialization only for certain methods模板特化仅适用于某些方法
【发布时间】:2015-07-14 09:59:23
【问题描述】:

我无法在我的 vec2 模板类中专门化某些方法。这是我的代码:

#pragma once

template<typename Number>
struct vec2
{
    static_assert(std::is_same<Number, int>::value
               || std::is_same<Number, float>::value
               || std::is_same<Number, double>::value,
               "Type not allowed. Use <int>, <float> or <double>.");
    Number x, y;

    vec2();
    vec2(Number x, Number y);

    void add(const vec2& other);
    inline Number lengthSquared() const;
    /*Some other general methods like this two*/
}

我的问题是:我想以这种方式专门化我的 length 方法:
如果模板类型是 int (vec2&lt;int&gt;)
,它必须返回 float 如果模板类型为 float (vec2&lt;float&gt;)
,它必须返回 float 如果模板类型是double (vec2&lt;double&gt;),它必须返回double

我以前像这样专门化我的length 方法:

struct vec2
{
/* ... */

inline Number length() const;
}
/*Outside vec2 struct, but in vec2.h*/
template<> inline int vec2<int>::length() const;
template<> inline float vec2<float>::length() const;
template<> inline double vec2<double>::length() const;

然后在我的 .cpp 文件中实现它。这很好用,但它只能返回相同的模板类型,它不能为vec2&lt;int&gt; 返回float length。有没有办法做到这一点?

【问题讨论】:

    标签: c++ templates vector specialization


    【解决方案1】:

    您可以编写一个辅助类型,在给定向量组件类型的情况下,为您提供length 的返回类型。

    template<typename T>
    struct vec_length_t {};
    
    // Specializations:
    template<>
    struct vec_length_t<int> { using type = float; };
    
    template<>
    struct vec_length_t<float> { using type = float; };
    
    template<>
    struct vec_length_t<double> { using type = double; };
    

    (或者给它一个更通用的名称以便在其他地方重复使用,例如 floatify 或类似名称)

    然后像这样使用它:

    template<typename Number>
    struct vec2 {
        ...
        typename vec_length_t<Number>::type length() const;
        ...
    };
    

    要复用多个函数或者在同一个类中使用,当然也可以使用局部类型别名:

    template<typename Number>
    struct vec2 {
        ...
        using length_t = typename vec_length_t<Number>::type;
        ...
        length_t length() const;
        ...
    };
    

    这使得在函数体中使用length_t 来调用正确的std::sqrt 重载变得容易(当您要返回float 时,您可能不想使用double 重载! ):

    template<typename Number>
    vec2<Number>::length_t vec2<Number>::length() const {
        // Note that x*x+y*y is a Number, but we want a length_t:
        return std::sqrt(static_cast<length_t>(x*x + y*y));
        // Or, if you have lengthSquared() defined as returning a Number:
        return std::sqrt(static_cast<length_t>(lengthSquared()));
    }
    

    【讨论】:

      【解决方案2】:

      有几种可能的选择:

      1) 使用某种形式的辅助特征模板来提供长度的返回类型:

        1234563潜在错误消息的可读性)
      • 也可以只为 int 提供此特征模板的专业化,并为其他所有内容提供通用版本,结合已经存在的 static_assert 将工作相同,但需要编写两个更少的专业化,但在我看来,知识然后,您的类处理的类型将分布在两个地方(特征和静态断言)

      2) 如果“一般”情况(双精度和浮点)的实现是相同的,并且只有 int 情况不同 - 也可以使用 false_type/true_type 的结果进行公共长度调用私有长度重载 is_same : ),可扩展性较差,但不需要任何外部类型:

      auto length() -> decltype(length(is_same<T, int>) { return length(is_same<T, int>); }
      Number length(std::false_type) { .... }
      float length(std::true_type) {....}
      

      当然,使用 C++14 可以摆脱 decltype mambo-jambo。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-13
        • 1970-01-01
        • 2020-10-24
        相关资源
        最近更新 更多