模板:class 专业化
Template : class specialization
我是 C++ 世界的新手。
抱歉我的新问题。
我有一个class
template <typename T>
class Foo
{
T t_;
void say_hello()
{ std::cout << "Ciao";}
// work with T ...
};
我想将此模板class专门用于 3 种类型。
If type is (A
or B
or C
), Then use this class
template<>
class Foo<A or B or C>
{
void say_hello()
{ std::cout << "Hello";}
};
最好的方法是什么?
谢谢你的帮助。
有几种可能,例如:
仅方法特化:
template<>
void Foo<A>::say_hello() { std::cout << "Hello"; }
template<>
void Foo<B>::say_hello() { std::cout << "Hello"; }
template<>
void Foo<C>::say_hello() { std::cout << "Hello"; }
或者,在 C++17 中,您可以这样做:
template <typename T>
class Foo
{
T t_;
void say_hello()
{
if constexpr(std::is_same_v<T, A> || std::is_same_v<T, B> || std::is_same_v<T, C>) {
std::cout << "Hello";
} else {
std::cout << "Ciao";
}
}
// work with T ...
};
虽然常规 if
在该示例中有效,但如果您调用特定于 A
、B
、C
的代码,它将失败。
if constexpr
不会有这个问题。
一种可能的解决方案是使用 SFINAE
template <typename T, typename = void>
class Foo
{
T t_;
void say_hello()
{ std::cout << "Ciao";}
// work with T ...
};
template <typename T>
class Foo<T, std::enable_if_t<std::is_same_v<T, A>,
|| std::is_same_v<T, B>,
|| std::is_same_v<T, C>>
{
void say_hello()
{ std::cout << "Hello";}
};
如果您不在 Foo
专业化中使用 T
(如您的示例所示),您也可以使用一种自我继承
template <typename T>
class Foo
{
T t_;
void say_hello()
{ std::cout << "Ciao";}
// work with T ...
};
template <>
class Foo<A>
{
void say_hello()
{ std::cout << "Hello";}
};
template <>
class Foo<B> : public Foo<A>
{ };
template <>
class Foo<C> : public Foo<A>
{ };
题外话:如果你想在 class 之外使用 say_hello()
,最好将它设为 public
(或者如果你将 Foo
声明为 struct
).
SFINAE 解决方案的一个变体,更加简洁类。
template<class T, class... Ts>
struct is_one_of;
template<class T, class Ts>
struct is_one_of<T, T, Ts...> : std::true_type {}; //maybe add std::decay_t
template<class T, class S, class Ts>
struct is_one_of<T, S, Ts...> : is_one_of<T, Ts...> {};
template<class T>
struct is_one_of<T> : std::false_type{};
template<class T, class... Ts>
constexpr bool is_one_of_v = is_one_of<T, Ts...>::value;
template <typename T, typename = void>
class Foo
{
T t_;
void say_hello()
{ std::cout << "Ciao";}
// work with T ...
};
template <typename T>
class Foo<T, std::enable_if_t<is_one_of_v<T, A, B, C>
{
void say_hello()
{ std::cout << "Hello";}
};
我是 C++ 世界的新手。 抱歉我的新问题。
我有一个class
template <typename T>
class Foo
{
T t_;
void say_hello()
{ std::cout << "Ciao";}
// work with T ...
};
我想将此模板class专门用于 3 种类型。
If type is (A
or B
or C
), Then use this class
template<>
class Foo<A or B or C>
{
void say_hello()
{ std::cout << "Hello";}
};
最好的方法是什么? 谢谢你的帮助。
有几种可能,例如:
仅方法特化:
template<>
void Foo<A>::say_hello() { std::cout << "Hello"; }
template<>
void Foo<B>::say_hello() { std::cout << "Hello"; }
template<>
void Foo<C>::say_hello() { std::cout << "Hello"; }
或者,在 C++17 中,您可以这样做:
template <typename T>
class Foo
{
T t_;
void say_hello()
{
if constexpr(std::is_same_v<T, A> || std::is_same_v<T, B> || std::is_same_v<T, C>) {
std::cout << "Hello";
} else {
std::cout << "Ciao";
}
}
// work with T ...
};
虽然常规 if
在该示例中有效,但如果您调用特定于 A
、B
、C
的代码,它将失败。
if constexpr
不会有这个问题。
一种可能的解决方案是使用 SFINAE
template <typename T, typename = void>
class Foo
{
T t_;
void say_hello()
{ std::cout << "Ciao";}
// work with T ...
};
template <typename T>
class Foo<T, std::enable_if_t<std::is_same_v<T, A>,
|| std::is_same_v<T, B>,
|| std::is_same_v<T, C>>
{
void say_hello()
{ std::cout << "Hello";}
};
如果您不在 Foo
专业化中使用 T
(如您的示例所示),您也可以使用一种自我继承
template <typename T>
class Foo
{
T t_;
void say_hello()
{ std::cout << "Ciao";}
// work with T ...
};
template <>
class Foo<A>
{
void say_hello()
{ std::cout << "Hello";}
};
template <>
class Foo<B> : public Foo<A>
{ };
template <>
class Foo<C> : public Foo<A>
{ };
题外话:如果你想在 class 之外使用 say_hello()
,最好将它设为 public
(或者如果你将 Foo
声明为 struct
).
SFINAE 解决方案的一个变体,更加简洁类。
template<class T, class... Ts>
struct is_one_of;
template<class T, class Ts>
struct is_one_of<T, T, Ts...> : std::true_type {}; //maybe add std::decay_t
template<class T, class S, class Ts>
struct is_one_of<T, S, Ts...> : is_one_of<T, Ts...> {};
template<class T>
struct is_one_of<T> : std::false_type{};
template<class T, class... Ts>
constexpr bool is_one_of_v = is_one_of<T, Ts...>::value;
template <typename T, typename = void>
class Foo
{
T t_;
void say_hello()
{ std::cout << "Ciao";}
// work with T ...
};
template <typename T>
class Foo<T, std::enable_if_t<is_one_of_v<T, A, B, C>
{
void say_hello()
{ std::cout << "Hello";}
};