多种类型的部分 class 模板专业化

Partial class template specialisation for multiple types

我有一个 class,它允许创建一个包含任何类型或 class 的向量。但是我想为数字类型添加额外的功能。

template <>
class Vec<double> : public VecBase<double>
{
    //  == METHODS ==
    public:
        //  -- Constructors & Destructors --
        explicit Vec(const unsigned long long t_size);
        virtual ~Vec();

        //  -- Operators --
        friend Vec<double> operator+(const Vec<double>&, const double);

        //  -- Methods --
        double sum();

... etc.

我已经部分特化了 class 模板以允许重载数学运算符以实现双重特化。我现在也想将此特化扩展到 int,但不是复制用 int 替换 double 的特化,有没有办法将它添加到特化列表中?

也就是说,有没有办法允许:

template<>
class Vec<double (or) int>

干杯!

我想你可以使用一个布尔默认值,就像下面例子中的foo结构

#include <iostream>

template <typename>
struct isSpecialType
 { static constexpr bool value { false }; };

template <>
struct isSpecialType<int>
 { static constexpr bool value { true }; };

template <>
struct isSpecialType<double>
 { static constexpr bool value { true }; };

template <typename T, bool = isSpecialType<T>::value>
struct foo;

template <typename T>
struct foo<T, true>
 { static constexpr bool value { true }; };

template <typename T>
struct foo<T, false>
 { static constexpr bool value { false }; };

int main()
 {
   std::cout << "- void value:   " << foo<void>::value << std::endl;
   std::cout << "- bool value:   " << foo<bool>::value << std::endl;
   std::cout << "- int value:    " << foo<int>::value << std::endl;
   std::cout << "- double value: " << foo<double>::value << std::endl;
 }

我们的想法是定义一种类型特征 (isSpecialType) 来选择所选类型(在您的示例中为 intdouble),布尔值是 false 在通用实现中,true 在专业化中。

template <typename>
struct isSpecialType
 { static constexpr bool value { false }; };

template <>
struct isSpecialType<int>
 { static constexpr bool value { true }; };

template <>
struct isSpecialType<double>
 { static constexpr bool value { true }; };

接下来,您必须声明 foo 结构(class Vec,在您的问题中),补充 bool 模板值和 isSpecialType<T>::value 默认值

template <typename T, bool = isSpecialType<T>::value>
struct foo;

最后,您必须实现 foo 的两个部分专用版本:第一个具有布尔值 true

template <typename T>
struct foo<T, true>
 { static constexpr bool value { true }; };

对应你的专业版Vec;具有 false 布尔值

的那个
template <typename T>
struct foo<T, false>
 { static constexpr bool value { false }; }; 

对应你的Vec.

的通用版本

还有一点:我的例子是C++11或更新的代码;如果你想要一个 C++98 版本,你只需将 bool 值定义为 const(而不是 constexpr)并使用 C++98 样式初始化它们;我是说

 static bool const bool value = true;

而不是

 static constexpr bool value { true };

当然有,但您可能会发现这已经在 http://en.cppreference.com/w/cpp/numeric/valarray

中完成

看看 std::enable_if 和 std::is_integral 和 std::is_floating_point。 (copied from cplusplus.com)

// enable_if example: two ways of using enable_if
#include <iostream>
#include <type_traits>

// 1. the return type (bool) is only valid if T is an integral type:
template <class T>
typename std::enable_if<std::is_integral<T>::value,bool>::type
  is_odd (T i) {return bool(i%2);}

// 2. the second template argument is only valid if T is an integral type:
template < class T,
           class = typename std::enable_if<std::is_integral<T>::value>::type>
bool is_even (T i) {return !bool(i%2);}

int main() {

  short int i = 1;    // code does not compile if type of i is not integral

  std::cout << std::boolalpha;
  std::cout << "i is odd: " << is_odd(i) << std::endl;
  std::cout << "i is even: " << is_even(i) << std::endl;

  return 0;
}

我和@max66 有同样的想法,但是你可以使用辅助函数来更容易地做到这一点。

#include <iostream>
#include <type_traits>

// helper
template <typename ...Ts>
struct allowed_types
{
    template <typename T>
    using check = std::disjunction<std::is_same<T, Ts>...>;

    template <typename T>
    inline static constexpr bool check_v = check<T>::value;
};

// usage
template <typename T, bool = allowed_types<double, float>::check_v<T>>
struct foo;

template <typename T>
struct foo<T, true> // for double and float
{
    inline static constexpr size_t value = 1;
};

template <typename T>
struct foo<T, false> // for other types
{
    inline static constexpr size_t value = 2;
};

int main()
{
    std::cout << foo<float>::value << '\n';  // 1
    std::cout << foo<double>::value << '\n'; // 1
    std::cout << foo<int>::value << '\n';    // 2
    std::cout << foo<char>::value << '\n';   // 2
}

只需输入您需要的任何一组类型即可。 例如:

template <typename T, bool = allowed_types<char, int, std::vector<int>>::check_v<T>>

编辑:
如果您需要将您的专业化分成 2 个以上的组,那么您需要使用 enable_if 方法。 有了上面的帮助,它可以这样写:

// default, for any type
template <typename T, typename = void>
struct foo
{
    inline static constexpr size_t value = 1;
};

// for double and float
template <typename T>
struct foo<T, std::enable_if_t<allowed_types<double, float>::check_v<T>>>
{
    inline static constexpr size_t value = 2;
};

// for int and char
template <typename T>
struct foo<T, std::enable_if_t<allowed_types<int, char>::check_v<T>>>
{
    inline static constexpr size_t value = 3;
};

int main()
{
    std::cout << foo<bool>::value << '\n';   // 1
    std::cout << foo<double>::value << '\n'; // 2
    std::cout << foo<float>::value << '\n';  // 2
    std::cout << foo<int>::value << '\n';    // 3
    std::cout << foo<char>::value << '\n';   // 3
}