模板模板和部分专业化:一个难题

Template template and partial specialization: a puzzle

本文关键字:一个 难题 专业化      更新时间:2023-10-16

请考虑以下代码:

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>>
不幸的是,由于模板模板、部分专业化和参数之间存在的依赖关系,它们共同导致了一个难题,我从几个小时以来一直在努力解决。

有什么聪明的解决方案可以做到这一点吗?
到目前为止,我已经能够用中间结构解决它,但我不太喜欢它......

部分专用化不接受默认参数,但主专用化接受默认参数。您可以在此处添加它:

template<typename Sig, typename X = S<return_type_t<Sig>>>
struct B;

然后,您需要做的就是为签名实现一个返回类型元函数。像这样:

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;
};

您可以为此创建一个帮助程序类:

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;

演示

在这里我们将B更改为模板别名。

B_t执行默认的参数工作。

B_impl是在没有任何默认参数的情况下实现B

B 是一个 using 别名,用于获取 B_t 的结果。

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上的模式匹配效果不佳。