简体   繁体   English

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

[英]Template specialization only for certain methods

I can't specialize some methods in my vec2 template class. 我无法在我的vec2模板类中专门研究某些方法。 Here's my code: 这是我的代码:

#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*/
}

My problem is: i want to specialize my length method this way: 我的问题是:我想这样专门化我的length方法:
it must return a float if template type is int ( vec2<int> ) 如果模板类型为intvec2<int> ),则必须返回float
it must return a float if template type is float ( vec2<float> ) 如果模板类型为floatvec2<float> ),则必须返回float
it must return a double if template type is double ( vec2<double> ) 如果模板类型为doublevec2<double> ),则必须返回double

I previously specialized my length method like this: 我以前像这样专门化了我的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;

and then implemented that in my .cpp file. 然后在我的.cpp文件中实现。 And that works fine but it can only return the same template type, it can't return a float length for a vec2<int> . 效果很好,但它只能返回相同的模板类型,而不能返回vec2<int>float length Is there a way to do that? 有没有办法做到这一点?

You can write a helper type which gives you the return type for length given the vector component type. 您可以编写一个帮助程序类型,该给定类型为给定矢量分量类型的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; };

(or give it a more general name to be reused somewhere else, like floatify or similar) (或者给它一个更通用的名称,以便在其他地方重用,例如floatify或类似名称)

Then use it like this: 然后像这样使用它:

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

To be reused for multiple functions or uses in the same class, you can of course also use a local type alias: 要重用于同一类中的多种功能或用途,您当然也可以使用本地类型别名:

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

This makes it easy to also use length_t in the function body to call the correct std::sqrt overload (you probably don't want to use the double overload when you are about to return a float !): 这使得在函数体中使用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()));
}

There are several possible options: 有几种可能的选择:

1) Use some form of helper traits template to provide the return type for length: 1)使用某种形式的helper traits模板来提供长度的返回类型:

  • if only specializations for the types you want to store in the template (int, float, double) are provided, then you could get rid of static_assert (although the static assert most likely has advantage when it comes to the readability of the potential error message) 如果仅提供要存储在模板中的类型的特殊化(int,float,double),那么您可以摆脱static_assert(尽管就潜在错误消息的可读性而言,静态断言最有可能具有优势) )

  • one could also provide specialization of this traits template only for int and provide generic version for everything else, combined with the static_assert already there would work the same but with two less specializations to write, but in my opinion the knowledge about the types handled by your class would then be spread in two places (traits and static assert) 一个人也可以只为int提供此特征模板的专业化,并为其他所有内容提供通用版本,再加上static_assert已经可以使用相同的功能,但是要写的专业性要少一些,但是在我看来,关于您所处理类型的知识然后将类散布在两个地方(特征和静态断言)

2) In case the implementation for the 'general' case (double and float) is the same and only int case is different - one could also make public length call private length overloads taking false_type/true_type with the result of is_same :), less expandable but without the need for any external types: 2)如果“通用”情况(双精度和浮点)的实现是相同的,并且只有int情形不同-可以使用is_same :)的结果使用false_type / true_type进行公共长度调用私有长度重载,更少可扩展,但不需要任何外部类型:

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

Of course with C++14 one could get rid of decltype mambo-jambo. 当然,使用C ++ 14可以摆脱decltype mambo-jambo。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM