包含格式错误的模板成员函数的格式良好的程序?

时间:2017-12-15 09:34:36

标签: c++ templates language-lawyer

在下面的代码片段中,我很困惑为什么Wrapper::f() const的定义不会使我的程序格式错误 1 尽管它调用了非const成员函数一个不可变的成员变量:

// well-formed program (???)
// build with: g++ -std=c++17 -Wall -Wextra -Werror -pedantic
template<class T> struct Data { void f() {} };

template<class T> struct Wrapper
{
    Data<T> _data;
    void f() const { _data.f(); } // _data.f(): non-const!
};

int main()
{
    Wrapper<void> w; // no error in instantiation point?
    (void) w;
}

demo 2

另一方面,如果Data是非模板类 3 ,我的编译器会发出诊断信息:

// ill-formed program (as expected)
// build with: g++ -std=c++17 -Wall -Wextra -Werror -pedantic
struct Data { void f() {} };

template<class T> struct Wrapper
{
    Data _data;
    void f() const { _data.f(); } //error: no matching function for call to 'Data::f() const'
};

int main()
{
    Wrapper<void> w;
    (void) w;
}

demo

我觉得答案将包含诸如&#34;演绎语境和#34;等表达式。 ......但我真的无法确定标准的确切部分,以表明这种行为。

是否有语言律师在此事上启发我?

注意:
  1)但如果我尝试有效调用 Wrapper<T>::f() const,我会收到错误。
  2)我使用-std=c++17编译但这不是特定于C ++ 17,因此没有特定的标记。
  3)this answer中,@ Baum mit Augen引用[N4140, 14.7.1(2)]

  

在需要成员定义存在的上下文中引用特化时,隐式实例化成员的特化

但是在编译片段(#2)中void f() const { _data.f(); }失败,尽管&#34;专业化是从不在需要成员定义存在的上下文中引用&# 34。

1 个答案:

答案 0 :(得分:4)

Snippet#2 格式错误

正如this answer中所述,只要有效的专业化可以生成Wrapper::f的模板定义就是格式良好的(因此不会发出任何描述)。

§17.7/8 [temp.res]州:

  

知道哪些名称是类型名称允许每个模板的语法   被检查。该程序格式错误,无需诊断,如果:

     
      
  • 无法为模板中的模板或constexpr if语句的子语句生成有效的专门化,并且   模板未实例化,或[...]
  •   

在两个代码段中都没有Wrapper<void>::f被实例化,因为§17.7.1/2 [temp.inst]中的规则:

  

类模板特化的隐式实例化导致   声明的隐式实例化,而不是   定义,[...]。

(强调我完成)

但是现在§17.7/ 8开始了:如果没有实例化,就没有生成的特化Wrapper::f的模板定义是有效的(情况就是这样)片段#2,对于每个生成的特化Wrapper<T>::f,在成员的non-const函数内进行const调用将被执行),程序格式错误并发布诊断。

但是因为诊断不是强制性的(参见上面的§17.7/ 8),GCC可以拒绝代码片段#2,而VSclang都可以完美地编译相同的代码。

对于代码段#1,您可以为Data提供用户定义的专门化,其中Data::fconst(例如Data<void>::f)。因此,Wrapper::f的有效生成的特化是可能的,即Wrapper<void>::f。总而言之,代码片段#1格式正确,代码片段#2无效;所有编译器都以符合标准的方式工作。