作为非类型模板参数引用

Reference as a non-type template argument

本文关键字:参数 引用 类型      更新时间:2023-10-16

下面的示例尝试使用引用类型的变量作为非类型模板参数(本身为引用类型(的参数。Clang,GCC和VC++都拒绝它。但是为什么?我似乎在标准中找不到任何使其非法的东西。

int obj = 42;
int& ref = obj;
template <int& param> class X {};
int main()
{
    X<obj> x1;  // OK
    X<ref> x2;  // error
}

现场示例


咕噜 说:

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

其他人则以类似的方式抱怨。


来自

标准(所有报价来自 C++11;C++14 在相关部分似乎没有重大变化(:

14.3.2/1 非类型、非模板模板参数的模板参数应为以下参数之一:

  • 一个常量表达式 (5.19(,用于指定具有静态存储持续时间和外部或内部链接的对象地址......表示(忽略括号(作为& id 表达式,除了&...如果相应的模板参数是引用,则应省略

现在什么是常量表达式:

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

    引用
  • 引用类型的变量或数据成员的 ID 表达式,除非引用具有前面的初始化,使用常量表达式初始化


据我所知,X<ref>中的ref是一个 id 表达式,它引用了引用类型的变量。此变量具有前面的初始化,使用表达式 obj 进行初始化。我相信obj是一个常量表达式,无论如何,如果不是,那么X<obj>也不应该编译。

  • 那么我错过了什么?
  • 标准中的哪个条款使X<ref>无效,而X<obj>是有效的?

简介

不过,引用

的名称是id表达式是正确的;id表达式不引用引用的任何内容,而是引用引用本身。

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

标准 (N4140(

您在帖子中引用了标准的相关部分,但您遗漏了最重要的部分(强调我的(:

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

类型、非模板模板参数的模板参数应为以下参数之一:

  • 一个常量表达式 (5.19(,它指定具有静态动态持续时间和外部或内部链接的完整对象的地址,或具有外部或内部链接的函数,包括函数模板和函数模板 ID,但不包括非静态类成员,表示(忽略括号(& id-表达式其中 id-expression 是对象或函数的名称,但如果名称引用函数或数组,则可以省略&,如果相应的模板参数是引用,则应省略;

注意:在早期的草案中,"其中id-expression是对象或函数的名称">不存在;DR 1570解决了这个问题 - 这无疑使意图更加清晰。

<小时 />

引用类型的变量不是对象

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

5p5 表达式 [expr]

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

<小时 />

阐述

非常重要的是要注意常量表达式("指定一个完整对象的地址......">( 必须是 &id-expressionid-expression 之一。

即使常量表达式(不仅仅是 id 表达式(可能引用具有静态存储持续时间的对象,我们也不能使用它来"初始化">引用指针类型的模板参数

示例代码段

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

注意:这也是我们不能使用字符串文字作为模板参数的原因;它们不是id表达式