我最近遇到了以下问题:
// 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)...);
}
我的问题是这两种方法都同样有效/可接受/技术上正确?如果是,出于某些微妙的技术或美学原因,是否更可取?为什么?
关于额外的上下文,我在原始代码中没有看到任何其他专业化,所以我不确定具有专业化的代码给我们带来了什么。
答案 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>
相同,MyVec
与 std::vector
不同
所以
struct Specialization<A<std::vector<int>>> {/*..*/};
没问题
而
struct Specialization<A<std::vector, int>> {/*..*/};
对于 A<MyVec, int>
来说会更成问题。