lol*_*pop 8 c++ language-lawyer explicit-instantiation c++-concepts c++20
这有效并输出“1”,因为函数的约束是部分排序的并且最受约束的重载获胜:
template<class T>
struct B {
int f() requires std::same_as<T, int> {
return 0;
}
int f() requires (std::same_as<T, int> && !std::same_as<T, char>) {
return 1;
}
};
int main() {
std::cout << B<int>{}.f();
}
Run Code Online (Sandbox Code Playgroud)
这也有效,因为显式实例化不会实例化不满足约束的成员函数:
template<class T>
struct B {
int f() requires std::same_as<T, int> {
return 0;
}
int f() requires (!std::same_as<T, int>) {
return 1;
}
};
template struct B<int>;
Run Code Online (Sandbox Code Playgroud)
那么这个应该怎么办呢?
template<class T>
struct B {
int f() requires std::same_as<T, int> {
return 0;
}
int f() requires (std::same_as<T, int> && !std::same_as<T, char>) {
return 1;
}
};
template struct B<int>;
Run Code Online (Sandbox Code Playgroud)
目前,这会导致 trunk gcc 崩溃,因为它编译了两个具有相同修饰的函数。我认为仅编译第二个函数是有意义的,以便行为与常规重载决议一致。标准中是否有任何内容可以处理这种边缘情况?
C++20 认识到相同的有效要求可以有不同的拼写。因此该标准定义了两个概念:“等效”和“功能等效”。
真正的“等价”是基于满足 ODR(单一定义规则):
如果包含表达式的两个函数定义满足单一定义规则,则两个涉及模板参数的表达式被视为等效,但用于命名模板参数的标记可能不同,只要在一个表达式中用于命名模板参数的标记是相同的即可。替换为在另一个表达式中命名相同模板参数的另一个标记。
还有更多内容,但这不是问题。
模板头的等效性包括所有约束表达式都是等效的(模板头包括约束)。
功能等价(通常)是指表达式的结果相等。对于模板头,两个不等价的 ODR 模板头可以在功能上等效:
如果两个模板头接受并满足 ([temp.constr.constr]) 同一组模板参数列表,则它们在功能上是等效的。
这部分基于约束表达式的有效性。
版本 1 和 3 中的两个模板头并不等效于 ODR,但它们在功能上是等效的,因为它们都接受相同的模板参数。如果代码的行为与 ODR 等效,则该代码的行为将有所不同。因此,这段话开始了:
如果程序的有效性或含义取决于两个构造是否等效,并且它们在功能上等效但不等效,则该程序是格式错误的,无需诊断。
因此,所有编译器都同样正确,因为您的代码是错误的。显然,编译器不应该直接崩溃(这应该作为错误提交),但“格式错误,无需诊断”通常会带来不可预见的后果。
| 归档时间: |
|
| 查看次数: |
283 次 |
| 最近记录: |