C++ 是否要求模板声明格式正确?

问题描述 投票:0回答:2

在 C++ 中,函数模板的类型检查被推迟到调用(实例化)模板函数为止。例如

template<typename T>
int right() {
    return T::f();
}

是合法的 C++ 代码,之后只要类型

right<Foo>()
有一个返回
Foo
的静态方法
f
,函数调用
int
就是合法的。

我观察到我的 C++ 编译器 (Clang) 可以捕获一些类型错误,只要它们不依赖于模板参数。例如

template<typename T>
int wrong1() {
    return "";
}

无法使用 Clang 16.0.0 进行编译(

char*
int
不兼容),即使模板函数从未被调用(实例化)。这就带来了一个问题:C++ 编译器是否要求模板函数声明类型正确(忽略依赖于模板参数的表达式)?或者这只是 Clang 的一个功能,它试图尽早捕获类型错误?

c++ templates clang clang++
2个回答
4
投票

模板定义中的任何非依赖构造,如果在其定义之后立即导致模板的假设实例化为格式错误,则会使程序 IFNDR(格式错误,无需诊断),这意味着没有要求C++ 标准规定了编译器如何处理此类程序。

在这种情况下,即使模板没有实际实例化,编译器也可以立即退出编译并出现错误,或者它可能会忽略它并仅在模板实际实例化时提供诊断。 (从技术上讲,它还可以做任何其他事情,例如编译程序但让它以意想不到的方式运行。IFNDR 实际上与所有输入的未定义行为相同。)

还有一些其他情况,可以在定义时检查模板定义的有效性,如果不满足[temp.res.general]/8中列出的某些要求,则导致程序成为 IFNDR。例如,如果模板实际上并未实例化,但模板的任何实例化都将是格式错误的。

但是除了列出的情况之外,编译器不允许退出编译或对可以实例化有效专业化的模板发出诊断。

非依赖”具有与构造是否依赖于模板参数相关的特定技术含义。有关参考,请参阅标准(草案)中的https://en.cppreference.com/w/cpp/language/dependent_name以及[temp.dep]

在您的示例中

T::f
是一个依赖名称,但第二个示例中的表达式
""
和返回类型不依赖于(类型/值)。此外,不可能在第二个示例中专门化模板,以便从
""
int
返回值的转换格式良好,而在第一个示例中可以定义并传递
T
的类型这样实例化就会格式良好。


0
投票

经过一番实验,我发明了这个代码片段

template<typename T>
int wrong2() {
    return [](){}; // error if instantiated: cannot assign lambda to int
}

Clang 16.0.0 不会报告此声明的类型错误,尽管它可能会报告类型错误,因为函数体

wrong2
不依赖于模板参数
T
并且可以立即进行类型检查,就像在原来的问题。由此可见,C++ 编译器不需要尽早捕获类型错误,尽管我在标准中找不到关于此主题的意见。
    

© www.soinside.com 2019 - 2024. All rights reserved.