包含格式错误的模板成员函数的格式正确的程序?
Well-formed program containing an ill-formed template member function?
在下面的代码片段中,我很困惑为什么Wrapper::f() const
的定义不会使我的程序格式错误1,尽管它调用了不可变成员变量的非常量成员函数:
// 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;
}
演示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;
}
演示
我觉得答案将包含诸如"推断上下文"之类的表达方式......但我真的无法确定标准中这种行为的确切部分。
有没有语言律师来启发我这件事?
注意:
1)但是如果我尝试有效地调用Wrapper<T>::f() const
,我会出错。
2)我已经用-std=c++17
编译了,但这并不特定于C++17,因此没有特定的标签。
3)在这个答案中,@Baum mit Augen引用了[N4140, 14.7.1(2)]
:
当在需要成员定义的存在的上下文中引用专用化时,将隐式实例化成员的专用化
但是在编译代码段中,void f() const { _data.f(); }
失败,尽管它的"在需要成员定义的上下文中从未引用过专用化"。
代码段 #2 格式不正确。
如本答案中所述,只要可以生成有效的专用化,Wrapper::f
的模板定义就是格式正确的(因此不会发出对角线)。
§17.7/8 [临时决议] 规定:
知道哪些名称是类型名称允许每个模板的语法 待检查。程序格式不正确,无需诊断,如果:
- 无法为模板或模板中的 constexpr if 语句的子语句生成有效的专用化,并且 模板未实例化,或 [...]
在这两个代码片段中,由于 §17.7.1/2 [temp.inst] 中的规则,Wrapper<void>::f
都没有被实例化:
类模板专用化的隐式实例化导致声明的隐式实例化,但不是 定义,[...]。
(强调由我完成)
但是现在 §17.7/8 开始了:如果没有实例化,并且不能生成Wrapper::f
模板定义有效的专用化(代码段 #2 就是这种情况,就像每个生成的专用化Wrapper<T>::f
一样,将在成员上的const
函数内执行non-const
调用), 程序格式不正确,已发出诊断程序。
但是由于诊断不是强制性的(参见上面的§17.7/8),GCC可以拒绝代码段#2,而VS和clang都可以完美地编译相同的代码。
但是,对于代码段 #1,您可以为Data::f
const
的Data
提供用户定义的专用化(例如Data<void>::f
)。因此,有效的、生成的Wrapper::f
专业化是可能的,即Wrapper<void>::f
.因此,总而言之,代码段 #1 格式正确,代码段 #2 无效;所有编译器都以符合标准的方式工作。
- Clang 格式 10.0 与 5.0 常量成员函数的格式不同
- 非静态成员函数的 decltype 格式不正确吗?
- C++ 编译错误:gnu_printf是无法识别的格式函数类型
- CPPCHECK C++成员函数上的格式字符串
- 对函数的 AST 声明的抽象格式感到困惑
- 获取 clang 格式以将多行函数调用的右括号放在单独的行上?
- 自定义 {fmt} 格式化函数,具有编译时格式字符串检查功能
- 保留短 lambda 用作函数的中间参数,使用 clang 格式保持不变
- clang格式:如何将构造函数的初始值设定项列表的每个元素保存在单独的行上
- clang格式:在 lambda 函数和外部块的大括号之前中断
- 包含格式错误的模板成员函数的格式正确的程序?
- 默认构造函数 C++ 格式
- “在成员函数之外封闭类的定义中需要默认成员初始值设定项” - 我的代码格式不正确
- 设置返回指向包含类的指针的函数的格式
- 是否允许复制/移动省略使使用已删除函数的程序格式正确?
- 如何在自己的函数中最好地处理Mat中的不同数字格式
- 继承类的构造函数的格式
- 奇怪的格式用于从构造函数中抛出异常
- 如何将GUI用户字符串输入转换为使用C++库函数的格式
- 具有 VS2012 NativeDEStepOver 注册表项,该注册表项阻止单步执行特定函数的格式更改