问题描述
${project_dir}/external/lib/
如果可以的话,该如何对类template<typename T>
class A { };
U x;
A<U> ... // OK
A<x> ... // ERROR
进行专门化处理,该类的参数是任何类型的对象?
解决方法
在考虑“参数是任何类型的对象”之前,我们应该首先了解“参数是对象”的局限性。 (另请参见How to use an object instance as template argument?)
请先进行以下说明: What's the difference between an argument and a parameter? 模板参数是定义中使用的占位符,例如此问题的<typename T>
。参数是使用定义时提供的替换,例如此问题的<U>
。
对象作为模板参数
从技术上讲,template parameter that is neither a type nor a template不能是类类型的对象,但是可以是对对象的(左值)引用。 C ++ 20 稍微放松了一下,但并非一直放松到“任何类型”,所以我暂时将忽略此警告。
在实践中,将参数从作为对象转换为作为引用只是语法上的麻烦。尽管如此,语义仍有重要意义:即使您认为对象是“相等的”,不同的对象也会产生不同的模板实例化。如果您忽略了这一点,则可能会不必要地膨胀您的代码。您确定这与您的目标一致吗?
对象作为模板参数
template argument that is neither a type nor a template必须是编译时常量。这是在讨论模板时经常听到的一种说法。但是,在处理参考文献时可能具有令人惊讶的含义。为了使对象引用成为编译时的constant expression,它必须使用static storage duration引用对象。也就是说,该对象必须是:
- 在命名空间范围内声明,
- 用
static
声明,或 - 用
extern
声明。
如果您考虑一下,这应该很有意义。引用需要引用对象的地址。只有程序开始时分配的对象才具有在编译时已知的地址。函数本地对象的地址取决于特定函数调用在调用堆栈中的位置,这是运行时质量。
虽然模板参数可以是对任何类型的对象的引用,但将任何类型的任何对象用作对应的参数并不是真的。
任何类型的模板参数
要遵守上述限制,允许任何类型的对象只是允许对象和允许类型的问题。有两件事可能会有所不同。其中之一可以隐藏在“ auto”关键字的后面。
template<const auto & Object>
class A {};
如果您想更严格地接受哪些类型(例如,类类型的对象,而不是基本类型的对象),则可以将各种type properties与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;
}
现在您知道自己可以做到这一点,请停止思考您是否应该。您可能不应该。也许只是过度工程?试图变得“酷”? How bad could it get?