template<typename T>
class A { };
U x;
A<U> ... // OK
A<x> ... // ERROR
如果可以,那么我们如何对参数是任何类型对象的类A
进行专门化?
在考虑"argument是任何类型的对象";,我们应该首先理解";argument是一个对象;。(另请参阅如何使用对象实例作为模板参数?(
在此之前需要澄清:参数和自变量之间的区别是什么模板参数是定义中使用的占位符,例如此问题的<typename T>
。自变量是使用定义时提供的替换项,例如此问题的<U>
。
对象作为模板参数
从技术上讲,既不是类型也不是模板的模板参数不能是类类型的对象,但它可以是对对象的(左值(引用C++20稍微放松了这一点,但并不是一直到";任何类型";,所以我暂时不理会这个警告
在实践中,将参数从对象转换为引用只是语法上的一点杂耍。尽管如此,这还是有一个重要的语义:不同的对象产生不同的模板实例化,即使你认为对象是";相等";。如果忽略这一点,您可能会不必要地夸大代码。你确定这与你的目标一致吗?
对象作为模板参数
既不是类型也不是模板的模板参数必须是编译时常数。这是讨论模板时经常听到的一句话。然而,在处理参考文献时,它可能有一个令人惊讶的含义。为了使对象引用成为编译时常量表达式,它必须引用具有静态存储持续时间的对象。也就是说,对象必须是:
- 在命名空间范围内声明
- 用
static
声明,或 - 用CCD_ 5声明
如果你仔细想想,这应该是有意义的。引用需要它所引用的对象的地址。只有在程序开始时分配的对象具有在编译时已知的地址。函数本地对象的地址取决于特定函数调用在调用堆栈中的位置,这是一种运行时质量。
虽然模板参数可以是对任何类型的对象的引用,但任何类型的对象都不能用作相应的参数
任何类型的模板参数
受上述限制,允许任何类型的对象只是允许一个对象和允许一个类型的问题。有两件事可能会有所不同。其中一个可以隐藏在";自动;关键字。
template<const auto & Object>
class A {};
如果您想对接受哪些类型(例如类类型的对象,而不是基本类型的对象(进行更严格的限制,那么SFINAE可以使用各种类型属性。
示例:
template<const auto & Object>
class A {};
// A class for demonstration purposes
class U {};
// A global variable (declared at namespace scope)
U x;
int main()
{
// A static variable
static U y;
// A local variable
U z;
// Try to instantiate the template
A<x> compiles;
A<y> fine;
//A<z> fails;
// Suppress unused variable warnings
(void) compiles;
(void) fine;
(void) z;
}
既然你知道你可以这样做,停下来想想你是否应该。你可能不应该。也许这只是有点过于工程化了?试图成为";酷";?情况会有多糟?