引用作为非类型模板参数 [英] Reference as a non-type template argument

查看:223
本文介绍了引用作为非类型模板参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的示例尝试将引用类型的变量用作非类型模板参数(引用类型本身)的参数。 Clang,GCC和VC ++都拒绝了它。但为什么?

The example below attempts to use a variable of reference type as an argument for a non-type template parameter (itself of reference type). Clang, GCC and VC++ all reject it. But why? I can't seem to find anything in the standard that makes it illegal.

int obj = 42;
int& ref = obj;

template <int& param> class X {};

int main()
{
    X<obj> x1;  // OK
    X<ref> x2;  // error
}

实时示例

CLang说:


source_file.cpp:9:7:错误:引用类型'int&'的非类型模板参数不是对象

source_file.cpp:9:7: error: non-type template argument of reference type 'int &' is not an object

其他人也以类似方式抱怨。

Others complain in similar ways.

根据标准(所有引号均来自C ++ 11; C ++ 14在相关部分似乎没有重大变化):

From the standard (all quotes from C++11; C++14 doesn't appear to have significant changes in relevant parts):


14.3.2 / 1 用于非类型,非模板 template-parameter template-argument 应该是以下之一:

14.3.2/1 A template-argument for a non-type, non-template template-parameter shall be one of:

...


  • 一个常量表达式(5.19),用于指定具有静态存储持续时间且外部或外部对象的地址内部链接...(忽略括号)表示为& id-expression ,但& ...应为如果相应的 template-parameter 是引用

  • a constant expression (5.19) that designates the address of an object with static storage duration and external or internal linkage ... expressed (ignoring parentheses) as & id-expression, except that the & ... shall be omitted if the corresponding template-parameter is a reference

...

现在是一个常量表达式:

Now what's a constant expression:


5.19 / 2 条件表达式核心常量表达式,除非它涉及以下之一作为可能评估的子表达式(3.2)...

5.19/2 A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression (3.2)...

...


  • id-expression 是指引用类型的变量或数据成员,除非引用具有先前的初始化,并且使用常量表达式初始化

  • an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization, initialized with a constant expression

...






据我所知, ref X< ref> 中的>是 id-expression ,它引用引用类型的变量。该变量具有一个先前的初始化,使用表达式 obj 进行初始化。我相信 obj 是一个常量表达式,如果不是,则 X< obj> 不应该


As far as I can tell, ref in X<ref> is an id-expression that refers to a variable of reference type. This variable has a preceding initialization, initialized with the expression obj. I believe obj is a constant expression, and anyway if it isn't, then X<obj> shouldn't compile either.


  • 那么我缺少什么了?

  • 标准中的哪个子句会呈现 X< ref> 无效,而 X< obj> 有效吗?

  • So what am I missing?
  • Which clause in the standard renders X<ref> invalid, while X<obj> is valid?

推荐答案

简介


正确的说法是引用的名称不过是 id-expression id-expression 不会引用任何引用,而是引用本身。

Introduction

It is correct saying that the name of a reference is an id-expression, though; the id-expression doesn't refer to whatever the reference is referencing, but the reference itself.

 int    a = 0;
 int& ref = a; // "ref" is an id-expression, referring to `ref` - not `a`




标准( N4140


您在帖子中引用了标准的相关部分,但您忽略了最重要的部分(强调我的内容):


The Standard (N4140)

You are quoting the relevant sections of the standard in your post, but you left out the most important part (emphasize mine):


14.3.2p1 模板非类型参数 [temp.arg.nontype]

14.3.2p1 Template non-type arguments [temp.arg.nontype]

用于非类型非模板的 template-argument template-parameter 应该是以下之一:

A template-argument for a non-type, non-template template-parameter shall be one of:


  • ...

一个常量表达式(5.19),它指定具有静态持续时间并具有外部或内部链接的完整对象的地址,或者具有外部或内部链接的函数,包括函数模板和函数
template-ids ,但不包括非静态类成员,表示为(忽略括号)为& i d-expression ,其中 id-expression 是对象或函数的名称,除了& ;如果相应的 template-parameter 是引用,则可以省略$ c; ...

a constant expression (5.19) that designates the address of a complete object with static sturage duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as & id-expression, where id-expression is the name of an object or function, except that the & may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; ...

注意::在较早的草案中,不存在,其中id-expression是对象或函数的名称 ;它由 DR 1570 解决-

Note: In earlier drafts "where id-expression is the name of an object or function" isn't present; it was addressed by DR 1570 - which undoubtedly makes the intent more clear.

您绝对正确;引用本身具有引用类型,并且只能在表达式的一部分时充当对象。

You are absolutely correct; the reference itself has reference type, and can merely act as an object when part of an expression.


5p5 表达式 [expr]

如果表达式最初的类型为对 T 的引用, (8.3.2,8.5.3),在进行任何进一步分析之前,将类型调整为 T 。表达式指定由引用表示的对象或函数,并且表达式是左值或x值,具体取决于表达式。

If an expression initially has the type "reference to T" (8.3.2, 8.5.3), the type is adjusted to T prior to any further analysis. The expression designates the object or function denoted by the reference, and the expression is an lvalue or an xvalue, depending on the expression.




阐述


请务必注意,常量表达式用于指定完整对象的地址... )必须是& id-expression id-expression 之一。


Elaboration

It is very important to note that the constant expression ("that designates the address of a complete object...") must be one of &id-expression, or id-expression.

即使 constant-expression 不仅仅是一个 id-expression ,它都可能引用具有静态存储期限的对象,我们不能使用它来初始化 引用-指针类型模板参数

Even though a constant-expression, that isn't just an id-expression, might refer to an object with static storage duration, we cannot use it to "initialize" a template-parameter of reference- or pointer type.

示例代码段

template<int&>
struct A { };

int            a = 0;
constexpr int& b = (0, a); // ok, constant-expression
A<(0, a)>      c = {};     // ill-formed, `(0, a)` is not an id-expression

注意:这也是我们不能使用 string-literals 作为 template-arguments 的事实的原因;它们不是 id表达式

Note: This is also a reason behind the fact that we cannot use string-literals as template-arguments; they are not id-expressions.

这篇关于引用作为非类型模板参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆