模板专门化仅适用于某些方法

时间:2015-07-14 09:59:24

标签: c++ templates vector specialization

我无法专注于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方法:
如果模板类型为floatint),则必须返回vec2<int> 如果模板类型为floatfloat),则必须返回vec2<float> 如果模板类型为doubledouble

,则必须返回vec2<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文件中实现它。并且工作正常,但它只能返回相同的模板类型,它不能为float length返回vec2<int>。有没有办法做到这一点?

2 个答案:

答案 0 :(得分:3)

您可以编写一个帮助器类型,在给定矢量组件类型的情况下,它为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重载变得很容易(当你即将发生时,你可能不想使用double重载返回float!):

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

答案 1 :(得分:2)

有几种可能的选择:

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

  • 如果只提供了要存储在模板中的类型(int,float,double)的特化,那么你可以摆脱static_assert(虽然静态断言最有可能具有优势)可能的错误信息的可读性)

  • 还可以为int提供这个traits模板的特化,并为其他所有东西提供泛型版本,结合static_assert已经有相同的工作但有两个不太专业化的写,但在我看来知识关于你的班级处理的类型将分散在两个地方(特征和静态断言)

2)如果'general'情况(double和float)的实现是相同的并且只有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。