Dav*_*man 5 c++ templates idioms partial-specialization
考虑以下系列的部分专业化:
template <typename T, typename Enable=void>
struct foo {
void operator()() const { cout << "unspecialized" << endl; }
};
template <typename T>
struct foo<T, enable_if_t<
is_integral<T>::value
>>{
void operator()() const { cout << "is_integral" << endl; }
};
template <typename T>
struct foo<T, enable_if_t<
sizeof(T) == 4
and not is_integral<T>::value
>>{
void operator()() const { cout << "size 4" << endl; }
};
template <typename T>
struct foo<T, enable_if_t<
is_fundamental<T>::value
and not (sizeof(T) == 4)
and not is_integral<T>::value
>>{
void operator()() const { cout << "fundamental" << endl; }
};
// etc...
Run Code Online (Sandbox Code Playgroud)
我一直看到这种事情(实际上,其他地方的另一个 StackOverflow 答案为类似问题提供了相同的模式)。虽然这有效,但此代码存在一些严重的可维护性问题,并且还排除了例如在上述代码位于库中的情况下具有更高优先级的用户级部分特化。表达这个想法的更好模式是什么?我觉得必须有一些东西(可能涉及继承和可变参数模板参数?)可以更干净和可维护地表达这个想法。(还假设每个特化是一个完整的类而不是一个简单的函子,所以重载的函数不能以简单的方式工作)。
所以自从问这个问题以来我就一直被这个问题困扰,而且我从未对最初的答案完全满意。经过多次摆弄和尝试/错误后,我想出了一种使用标签调度的模式,我对此非常满意。它是否实际上比以前的答案更好、更具可读性和更可维护性由你来判断,但我更喜欢它。随意地拆开它、批评它、打破它。:-)
话不多说,这是解决问题的最简单版本的代码
template <typename> struct always_true : true_type { };
template <typename> struct always_false : false_type { };
template <typename T, template <class...> class condition=always_false,
typename flag=integral_constant<bool, condition<T>::value>
>
struct foo;
////////////////////////////////////////
// "unspecialized" version
// put always_true and false_type together here so that no one gets here accidentally
template <typename T, typename true_or_false_type>
struct foo<T, always_true, true_or_false_type> {
void operator()() const { cout << "unspecialized" << endl; }
};
////////////////////////////////////////
// is_fundamental
template <typename T>
struct foo<T, is_fundamental, true_type> {
void operator()() const { cout << "is_fundamental" << endl; }
};
template <typename T> struct foo<T, is_fundamental, false_type> : foo<T, always_true> { };
////////////////////////////////////////
// is_integral
template <typename T>
struct foo<T, is_integral, true_type> {
void operator()() const { cout << "is_integral" << endl; }
};
template <typename T>
struct foo<T, is_integral, false_type> : foo<T, is_fundamental> { };
////////////////////////////////////////
// sizeof(T) == 4
template <typename T>
using size_is_4 = integral_constant<bool, sizeof(T) == 4>;
template <typename T>
struct foo<T, size_is_4, true_type> {
void operator()() const { cout << "size_is_4" << endl; }
};
template <typename T>
struct foo<T, size_is_4, false_type> : foo<T, is_integral> { };
////////////////////////////////////////
// Now put the most specialized condition in the base of this template
template <typename T, typename true_or_false_type>
struct foo<T, always_false, true_or_false_type> : foo<T, size_is_4> { };
Run Code Online (Sandbox Code Playgroud)
在前面的答案中,优先级链保存在辅助结构中,并在继承中进行编码。
添加以比库的优先级更高的优先级启用用户部分专业化的能力需要做更多的工作,但原理是相同的。此演示中的完整版本。