简体   繁体   English

模板 Class Object Arguments 的专业化

[英]Template Class Specialization for Object Arguments

template<typename T>
class A { };

U x;
A<U> ... // OK
A<x> ... // ERROR

If we can, then how do we make a specialization of class A whose argument is an object of any type?如果可以,那么我们如何对 class A进行专门化,其参数是任何类型的 object?

Before considering "argument is an object of any type", we should first understand the limitations for "argument is an object".在考虑“argument is an object of any type”之前,我们应该首先了解“argument is an object”的限制。 (See also How to use an object instance as template argument? ) (另请参阅如何使用 object 实例作为模板参数?

A clarification before getting into this: What's the difference between an argument and a parameter?在进入这个之前的澄清: 参数和参数之间有什么区别? A template parameter is the placeholder used in a definition, such as this question's <typename T> .模板参数是定义中使用的占位符,例如这个问题的<typename T> An argument is the replacement provided when the definition is used, such as this question's <U> .参数是使用定义时提供的替换,例如这个问题的<U>

Objects as template parameters对象作为模板参数

Technically, a template parameter that is neither a type nor a template cannot be an object of class type, but it can be a (lvalue) reference to an object.从技术上讲, 既不是类型也不是模板的模板参数不能是 class 类型的 object,但它可以是对 object 的(左值)引用。 C++20 relaxes this a bit but not all the way to "any type", so I'll ignore this caveat for now. C++20稍微放宽了这一点,但并没有完全放宽到“任何类型”,所以我现在将忽略这个警告。

In practice, converting a parameter from being an object to being a reference is just a bit of syntax juggling.在实践中,将参数从 object 转换为引用只是一些语法上的杂耍。 Still, there is an important bit of semantics to this: different objects produce different template instantiations, even if you believe the objects to be "equal".尽管如此,这还是有一些重要的语义:不同的对象会产生不同的模板实例化,即使您认为这些对象是“相等的”。 If you ignore this point, you might needlessly bloat your code.如果你忽略这一点,你可能会不必要地膨胀你的代码。 Are you sure this is consistent with your goal?你确定这与你的目标一致吗?

Objects as template arguments对象作为模板 arguments

A template argument that is neither a type nor a template must be a compile-time constant. 既不是类型也不是模板的模板参数必须是编译时常量。 This is a refrain that is commonly heard when discussing templates.这是讨论模板时经常听到的副词。 However, it has a perhaps surprising implication when dealing with references.但是,在处理引用时,它可能具有令人惊讶的含义。 In order for an object reference to be a compile-time constant expression , it must refer to an object with static storage duration .为了使 object 引用成为编译时常量表达式,它必须引用具有static 存储持续时间的 object。 That is, the object must be:也就是说,object 必须是:

  • declared at namespace scope,在命名空间 scope 声明,
  • declared with static , orstatic声明,或
  • declared with extern .extern声明。

This should make sense if you think about it.如果您考虑一下,这应该是有道理的。 A reference needs the address of the object to which it refers.引用需要它所引用的 object 的地址。 Only an object that is allocated when the program begins has an address that is known at compile time.只有在程序开始时分配的 object 具有在编译时已知的地址。 The address of an object local to a function depends on where in the call stack that particular function call lies, which is a run-time quality. function 本地的 object 的地址取决于特定 function 调用在调用堆栈中的位置,这是运行时质量。

While a template parameter could be a reference to an object of any type, it is not true that any object of any type could be used as the corresponding argument.虽然模板参数可以是对任何类型的 object 的引用,但任何类型的任何object 都不能用作相应的参数。

Template parameter of any type任何类型的模板参数

Subject to the above restrictions, allowing an object of any type is just a matter of allowing an object and allowing a type.根据上述限制,允许任何类型的 object 只是允许 object 和允许类型的问题。 There are two things that can vary.有两件事可能会有所不同。 One of these can hide behind the "auto" keyword.其中之一可以隐藏在“auto”关键字后面。

template<const auto & Object>
class A {};

If you want to be more restrictive about which types are accepted (such as objects of class type, as opposed to objects of fundamental type), there are various type properties that can be used with SFINAE .如果您想更严格地限制接受哪些类型(例如 class 类型的对象,而不是基本类型的对象),可以使用各种类型属性SFINAE

Example:例子:

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;
}

Now that you know you could do this, stop to think if you should .既然您知道您可以做到这一点,请停止思考是否应该这样做。 You probably should not.你可能不应该。 Maybe it's just a bit of over-engineering?也许这只是有点过度设计? Trying to be "cool"?试图变得“酷”? How bad could it get?能坏到什么地步?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM