模板模板和偏特化:一个难题
Template template and partial specialization: a puzzle
考虑以下代码:
template<typename>
struct S { };
template<typename, typename>
struct B;
template <typename R, typename... Args, template<class> class C>
struct B<R(Args...), C<R>> {
void f() { }
};
int main() {
B<void(), S<void>> b;
b.f();
}
编译没有问题
无论如何,无论何时决定使用B
,它都必须提供两种类型。
我想要实现的是以某种方式默认第二个参数(我知道,部分特化不接受其参数的默认值)并让用户将其类型定义为 B<void()>
而不是 B<void(), S<void>>
。
不幸的是,由于模板模板、部分特化和参数之间存在的依赖性,它们一起导致了一个难题,几个小时以来我一直在努力解决这个难题。
有什么巧妙的解决方案吗?
到目前为止,我已经能够用中间结构解决它,但我不太喜欢它...
您可以为此创建一个助手 class:
template <typename T> struct default_arg;
template <typename R, typename... Args>
struct default_arg<R(Args...)>
{
using type = S<R>;
};
template<typename Sign, typename T = typename default_arg<Sign>::type>
struct B;
部分专业化不接受默认参数,但主要专业化接受。您可以将其添加到此处:
template<typename Sig, typename X = S<return_type_t<Sig>>>
struct B;
那么你需要做的就是为签名实现一个return类型的元函数。类似于:
template <class Sig>
struct return_type;
template <class Sig>
using return_type_t = typename return_type<Sig>::type;
template <class R, class... Args>
struct return_type<R(Args...)> {
using type = R;
};
这里我们把B
改成模板别名
B_t
默认 arg 工作。
B_impl
是 B
的实现,没有任何默认参数。
B
是获得 B_t
.
结果的 using
别名
template<class> struct S {};
template<class, class>
struct B_impl;
template<class R, class... Args, template<class...> class C>
struct B_impl<R(Args...), C<R>> {
void f() { }
};
template<class, class=void>
struct B_t;
template<class R, class...Args>
struct B_t<R(Args...), void>:
B_t<R(Args...),S<R>>
{};
template<class R, class... Args, template<class...> class C>
struct B_t<R(Args...), C<R>> {
using type=B_impl<R(Args...), C<R>>;
};
template<class Sig, class Z=void>
using B=typename B_t<Sig,Z>::type;
缺点是 B
上的模式匹配效果不佳。
考虑以下代码:
template<typename>
struct S { };
template<typename, typename>
struct B;
template <typename R, typename... Args, template<class> class C>
struct B<R(Args...), C<R>> {
void f() { }
};
int main() {
B<void(), S<void>> b;
b.f();
}
编译没有问题
无论如何,无论何时决定使用B
,它都必须提供两种类型。
我想要实现的是以某种方式默认第二个参数(我知道,部分特化不接受其参数的默认值)并让用户将其类型定义为 B<void()>
而不是 B<void(), S<void>>
。
不幸的是,由于模板模板、部分特化和参数之间存在的依赖性,它们一起导致了一个难题,几个小时以来我一直在努力解决这个难题。
有什么巧妙的解决方案吗?
到目前为止,我已经能够用中间结构解决它,但我不太喜欢它...
您可以为此创建一个助手 class:
template <typename T> struct default_arg;
template <typename R, typename... Args>
struct default_arg<R(Args...)>
{
using type = S<R>;
};
template<typename Sign, typename T = typename default_arg<Sign>::type>
struct B;
部分专业化不接受默认参数,但主要专业化接受。您可以将其添加到此处:
template<typename Sig, typename X = S<return_type_t<Sig>>>
struct B;
那么你需要做的就是为签名实现一个return类型的元函数。类似于:
template <class Sig>
struct return_type;
template <class Sig>
using return_type_t = typename return_type<Sig>::type;
template <class R, class... Args>
struct return_type<R(Args...)> {
using type = R;
};
这里我们把B
改成模板别名
B_t
默认 arg 工作。
B_impl
是 B
的实现,没有任何默认参数。
B
是获得 B_t
.
using
别名
template<class> struct S {};
template<class, class>
struct B_impl;
template<class R, class... Args, template<class...> class C>
struct B_impl<R(Args...), C<R>> {
void f() { }
};
template<class, class=void>
struct B_t;
template<class R, class...Args>
struct B_t<R(Args...), void>:
B_t<R(Args...),S<R>>
{};
template<class R, class... Args, template<class...> class C>
struct B_t<R(Args...), C<R>> {
using type=B_impl<R(Args...), C<R>>;
};
template<class Sig, class Z=void>
using B=typename B_t<Sig,Z>::type;
缺点是 B
上的模式匹配效果不佳。