Ami*_*rsh 4 c++ templates one-definition-rule friend-function language-lawyer
以下代码编译时没有任何错误,但它似乎破坏了 ODR:
#include <iostream>
template<long Num>
class B;
template<long Num>
struct A {
template<long Num1>
friend void ffoo(A<Num1> a, B<Num>* = nullptr) {
std::cout << "@A ffoo(A<" << Num1 << ">, B<" << Num << ">*)" << std::endl;
}
};
template<long Num>
class B {
public:
friend void ffoo(A<Num> a, B<Num>* = nullptr) {
std::cout << "@B ffoo(A<" << Num << ">, B<" << Num << ">*)" << std::endl;
}
};
int main() {
ffoo(A<1>{}); // @A ffoo(A<1>, B<1>*)
B<1>* ptr = nullptr;
ffoo(A<1>{}, ptr); // @B ffoo(A<1>, B<1>*)
}
Run Code Online (Sandbox Code Playgroud)
该ODR规则允许哪些情况下ODR的突破是IFNDR(病没有形成诊断所需的)所有这些情况似乎都与多个翻译单元程序。
该第一段是相当明确说明从单一的翻译单元的要求:
[basic.def.odr]/1
任何翻译单元不得包含任何变量、函数、类类型、枚举类型、模板、参数的默认参数(对于给定范围内的函数)或默认模板参数的多个定义。
上面的代码会破坏 ODR 吗?如果是这样,在单个翻译单元内打破 ODR 是否需要编译器诊断?
*注意:代码示例中的朋友模板函数似乎确实遵守了[temp.inst]的新规则。
的朋友B不是函数模板。那个朋友声明不是模板声明,所以我们有
[temp.friend](强调我的)
1类或类模板的朋友可以是函数模板或类模板,函数模板或类模板的特化,或非模板函数或类。对于不是模板声明的友元函数声明:
如果友元的名称是限定或非限定的模板ID,友元声明指的是函数模板的特化,否则,
如果友元的名称是限定 ID 并且在指定的类或命名空间中找到匹配的非模板函数,则友元声明引用该函数,否则,
如果友元的名称是限定 ID 并且在指定的类或命名空间中找到匹配的函数模板,则友元声明引用该函数模板的推导特化([temp.deduct.decl]),否则,
该名称应是声明(或重新声明)非模板函数的非限定 ID。
所以这两个声明ffoo不声明同一个实体。一个是函数模板,另一个是非模板函数。这两个可能与重载存在于同一声明区域中。
所以这里没有 ODR 违规。