多种类型的部分 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
) 来选择所选类型(在您的示例中为 int
和 double
),布尔值是 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
}
我有一个 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
) 来选择所选类型(在您的示例中为 int
和 double
),布尔值是 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
}