是全局变量constexpr的地址吗?

时间:2016-12-11 10:29:56

标签: c++11 language-lawyer

考虑以下

struct dummy{};

dummy d1;
dummy d2;

template<dummy* dum>
void foo()
{
    if (dum == &d1)
        ; // do something
    else if (dum == &d2)
        ; // do something else
}

现在,可以像这样调用foo

foo<&d1>();
foo<&d2>();

一切都按预期工作。但是以下不是

constexpr dummy* dum_ptr = &d1;
foo<dum_ptr>();

Visual Studio出现此错误

  

错误C2975:dum_ptrfoo的模板参数无效,预期编译时常量表达式

虽然这有效

constexpr dummy& dum_ref = d1;
foo<&dum_ptr>();

在visual studio中,但不是在G ++中,因为

  

注意:模板参数扣除/替换失败:
  错误:& dum_ref不是dummy*的有效模板参数,因为它不是变量的地址

foo<&dum_ref>();

编辑:
从C ++ 17开始,std::addressof被标记为constexpr,所以我猜它应该有效。

1 个答案:

答案 0 :(得分:4)

海湾合作委员会是对的。

表达式绝对是constant-expression s *,因为它们被分配给constexpr变量。但是,在c ++ 14之前,对指针模板参数允许的内容还有其他限制。

  

C ++ 14草案N4140 [temp.arg.nontype]

     

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

     
      
  • 表示整数或枚举类型的非类型模板参数,转换后的常量表达式(5.19)的类型   模板参数;或
  •   
  • 非类型模板参数的名称;或
  •   
  • 一个常量表达式(5.19),用于指定具有静态存储持续时间和外部或内部的完整对象的地址   连接或具有外部或内部联系的功能,包括   函数模板和函数template-id但不包括非静态   类成员,表达(忽略括号)为   &id-expression,其中id-expression是对象的名称或   功能,除了&amp;如果名称引用a,则可以省略   函数或数组,如果相应则应省略   template-parameter是一个引用;或
  •   
  • 一个求值为空指针值的常量表达式(4.10);要么       一个常量表达式,其值为null成员指针值(4.11);要么       指向成员的指针,如5.3.1所述;要么       类型为std :: nullptr_t的常量表达式。
  •   

对于foo<dum_ptr>()dum_ptr不表示为&name,而对于foo<&dum_ref>()dum_ref不是对象的名称,它是对象的引用名称,因此两者都不允许作为模板参数。

这些限制在c ++ 17中解除,以允许任何constexpr,这就是为什么它在那里工作:

  

C ++ 17 draft N4606 - 14.3.2模板非类型参数[temp.arg.nontype]

     

1非类型模板参数的模板参数应为a   转换常数表达式(5.20)的类型   模板参数。对于非类型模板参考或参考   指针类型,常量表达式的值不得参考   (或者对于指针类型,不应该是地址):

     
      
  • (1.1)子对象(1.8),
  •   
  • (1.2)临时对象(12.2),
  •   
  • (1.3)字符串文字(2.13.5),
  •   
  • (1.4)typeid表达式(5.2.8)或
  • 的结果   
  • (1.5)预定义的__func__变量(8.4.1)。
  •   

像往常一样,clang会给出最好的错误消息: https://godbolt.org/g/j0Q2bV

*(参见地址常量表达式参考常量表达式