使用可变模板的专门化作为模板参数
Using a specialization of variadic template as a template argument
考虑以下内容:
template <class...>
struct MyT;
template <class T>
struct MyT<T> {};
template <template <class> class TT = MyT> struct A {}; // fine
using B = A<MyT>; // does not compile
int main() {
return 0;
}
当MyT
被用作A
的默认参数时,编译器(g++ 5.4.0)很高兴。然而,当它被用来实例化A
时,情况就不同了:
temp.cpp:19:16: error: type/value mismatch at argument 1 in template parameter list for ‘template<template<class> class TT> struct A’
using B = A<MyT>;
^
temp.cpp:19:16: note: expected a template of type ‘template<class> class TT’, got ‘template<class ...> struct MyT’
我可以通过引入别名来修复它:
template <class T>
using MyTT = MyT<T>;
using B = A<MyTT>; // fine
问题是:错误的原因是什么,有没有不引入别名的解决方案?
EDIT请注意,A
被声明为具有模板模板参数,如图所示,并且没有给出更改
不能这样做,也不能将这种类型用作默认参数。事实上,它似乎是接受,只要你不依赖它并不意味着默认参数是有效的。
考虑以下显式使用默认类型的代码:
template <class...>
struct MyT;
template <class T>
struct MyT<T> {};
template <template <class> class TT = MyT> struct A {}; // fine
int main() {
A<> a;
return 0;
}
错误很明显:
在这种情况下,没有考虑到部分专门化,因此两个声明不同。template template实参与对应的模板形参
有不同的模板形参
您应该将
A
声明为:
template <template <class...> class TT = MyT> struct A;
或者在某个地方声明一个约束为单个参数的类型,例如通过using声明
首先,默认参数也不起作用。
第二,模板模板实参是一头奇怪的野兽。如果模板模板实参接受任何可以用模板模板实参中描述的签名实例化的东西,这是有意义的。
不是这样的。
相反,它以另一种方式工作。
template<template<class...>class Z> struct foo {};
template<template<class >class Z> struct bar {};
template<class...>struct a{};
template<class >struct b{};
foo
将接受a
或 b
。
bar
只接受 b
正确的回应,一旦你明白了,是"什么鬼?"如果你的回答不是"管他的",回头看看你是否能理解。这基本上是从c++中典型的参数类型向后工作的;它的行为更像是返回类型而不是参数。(如果你想了解一些可以让你直接讨论这个问题的语言,请学习术语逆变和协方差)
这是相当不直观的,为什么它以这种方式工作将涉及到追溯c++的历史。
但是,作为一个好处,template<class...>class
实参实际上是"任何只接受类型形参的模板"。我觉得这非常有用。
作为一个缺点,template<class>class
参数几乎是完全无用的。
Tl;dr:使您的template<template
参数为template<template<class...>class
,并且只使用只接受类型的模板的元程序。如果您有一个接受值的模板,请编写一个类型包装器,将std::size_t X
的需求替换为std::integral_constant< std::size_t, X >
。
暂时忘记了"你为什么要这样做?"如果你没有做任何模板专门化,第一个版本也可以工作。
template <class T>
struct MyT { };
template <template <class> class TT = MyT> struct A
{};
using B = A<MyT>;
对于模板专门化,编译器必须确定最佳匹配,但由于您从未实际提供任何模板参数,因此它是模糊的。
当你引入MyTT
时,你使用了一个模板参数,当只有一个参数时,编译器足够聪明,可以看到你有一个专门化:
template <class T>
using MyTT = MyT<T>;
在本例中,它选择专门化而不是可变的版本。
但是现在我们回到那个大问题…为什么?除非在A
中您总是使用特定的类实例化MyT
,否则使用A
根本没有意义:
template<template<class> class TT = MyT> struct A
{
// use an instance of TT??
TT<int> myInstance; // forced to choose `int`
};
我想把你的问题分成两部分。
A)考虑你的结构模板更简单template <class T>
struct TestStruct {
};
template <
template <class>
class TT = TestStruct
>
struct A
{
int a; // sorry to modify this. This help to show how it works
};
int main() {
A< TestStruct > b;
b.a; // it works!
return 0;
}
它可以工作,因为模板类TT只接受带有<类……>模板。特化类不依赖于此(因为它的底层仍然是模板<类……>)
B)即使你更新你的结构A到模板
template <class...>
struct MyT;
template <class T>
struct MyT<T> {
int a;
};
template <
template <class...>
class TT = MyT
// may be you need to add some more typename here, such as
// typename T1, ... , and then TT<T1> a;
>
struct A
{
TT<int> a;
// Here ! TT is a template only, do not have the template parameters!!!
};
int main() {
A< MyT > b;
b.a; // it works!!
return 0;
}
但是,如果你真的不能更新这些定义的签名,你可以做一个代理类
template< class T >
struct Proxy : MyT<T>
{
};
- 是否可以对零模板参数进行模板专门化
- 我能否根据其运算符()的签名专门化可变参数模板参数
- 取消专门化C++模板参数
- 模板函数,其中一个参数需要专门化,而另一个不需要
- 如何为特定数量的模板参数专门化可变参数模板结构
- 使用非类型模板参数进行专门化模板模板参数
- g++和clang++在结构/类专门化中具有非类型参数的不同行为
- 我如何避免使用依赖于参数的查找明确专门化模板化功能
- 专门化采用通用引用参数的函数模板
- 如果需要参数包,则使用SFINAE专门化类
- c++多参数模板化的类成员专门化
- C++11`using`关键字:专门化模板参数的模板别名
- 如何在没有参数的情况下专门化模板类
- 我可以用非模板类专门化一个可变模板模板模板参数吗
- 如何在C++中专门化 std::vector 的模板模板参数
- 使用已推导的模板参数专门化模板成员函数
- 如何根据类的模板参数专门化模板成员函数?
- 基于嵌套的内部参数专门化模板
- 如何用模板模板参数专门化模板类的成员
- 使用模板类作为参数专门化模板结构