在这种情况下可以避免模板特化吗?

时间:2021-07-08 11:25:55

标签: c++ templates

我最近遇到了以下问题:

// declare
template <class> struct A;
// specialise
template <template <class...> class C, class... Fields> struct A<C<Fields...>> {
  template <typename... Args> explicit A(C<Fields...>* c, Args&&... args) {}
};
// instantiate
template <template <class...> class C, class... Fields, class... Args>
A<C<Fields...>> MakeA(C<Fields...>* c, Args&&... args) {
  return A<C<Fields...>>(c, std::forward<Args>(args)...);
}

如果我理解正确的话(上面的评论是我的),它是将 A 声明为模板,然后专门化 A,其余的或多或少很简单。

为什么我们需要这样做而不是能够直接定义模板,类似于以下内容(据我所知,它可以编译并且似乎具有其他功能):

template <template <typename...> class C, typename... Fields> struct A1 {
 public:
  template <typename... Args> explicit A1(C<Fields...>* c, Args&&... args) {}
};

template <template <typename...> class C, typename... Fields, typename... Args>
A1<C, Fields...> MakeA1(C<Fields...>* c, Args&&... args) {
  return A1<C, Fields...>(c, std::forward<Args>(args)...);
}

我的问题是这两种方法都同样有效/可接受/技术上正确?如果是,出于某些微妙的技术或美学原因,是否更可取?为什么?

关于额外的上下文,我在原始代码中没有看到任何其他专业化,所以我不确定具有专业化的代码给我们带来了什么。

1 个答案:

答案 0 :(得分:1)

它们的使用语法不同:

第一个片段是

A<std::vector<int>> a(&some_vector, 42, 51);

而第二个是

A<std::vector, int> a(&some_vector, 42, 51);

这确实可以通过 MakeA 缓解。

但是,模板中的差异可能很重要,您需要“传播”不同的签名:

template <typename T>
void foo(T *t)
{
    A<T> a(t);
    // ...
}

对比

template <template <typename> class C,  typename... Ts>
void foo(C<Ts...> *t)
{
    A<C, Ts...> a(t);
    // ...
}

额外的警告是针对专业化和模板别名:

template <typename T>
using MyVec = std::vector<T>;

MyVec<T>std::vector<T> 相同,MyVecstd::vector 不同

所以

struct Specialization<A<std::vector<int>>> {/*..*/};

没问题

struct Specialization<A<std::vector, int>> {/*..*/};

对于 A<MyVec, int> 来说会更成问题。