在一个 TU 内破坏 ODR?
Breaking of ODR inside one TU?
以下代码 compiles without any error,虽然它似乎破坏了 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>*)
}
ODR Rules 允许打破 ODR 的情况是 IFNDR(格式错误,不需要诊断)所有这些情况似乎都与具有多个翻译单元的程序有关。
first paragraph 非常清楚地说明了单个翻译单元的要求:
[basic.def.odr]/1
No translation unit shall contain more than one definition of any variable, function, class type, enumeration type,
template, default argument for a parameter (for a function in a given
scope), or default template argument.
以上代码是否破坏了 ODR?如果是这样,打破单个翻译单元内的 ODR 是否需要编译器诊断?
* 注意:代码示例中的 friend 模板函数 似乎确实遵守新规则共 [temp.inst].
B
的好友不是函数模板。友元声明不是模板声明,所以我们有
[temp.friend] (emphasis mine)
1 A friend of a class or class template can be a function template
or class template, a specialization of a function template or class
template, or a non-template function or class. For a friend function
declaration that is not a template declaration:
if the name of the friend is a qualified or unqualified template-id, the friend declaration refers to a specialization of a function
template, otherwise,
if the name of the friend is a qualified-id and a matching non-template function is found in the specified class or namespace,
the friend declaration refers to that function, otherwise,
if the name of the friend is a qualified-id and a matching function template is found in the specified class or namespace, the friend
declaration refers to the deduced specialization of that function
template ([temp.deduct.decl]), otherwise,
the name shall be an unqualified-id that declares (or redeclares) a non-template function.
所以 ffoo
的两个声明没有声明同一个实体。一种是函数模板,另一种是非模板函数。这两个可能存在于与重载相同的声明区域中。
所以这里没有ODR违规。
以下代码 compiles without any error,虽然它似乎破坏了 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>*)
}
ODR Rules 允许打破 ODR 的情况是 IFNDR(格式错误,不需要诊断)所有这些情况似乎都与具有多个翻译单元的程序有关。
first paragraph 非常清楚地说明了单个翻译单元的要求:
[basic.def.odr]/1
No translation unit shall contain more than one definition of any variable, function, class type, enumeration type, template, default argument for a parameter (for a function in a given scope), or default template argument.
以上代码是否破坏了 ODR?如果是这样,打破单个翻译单元内的 ODR 是否需要编译器诊断?
* 注意:代码示例中的 friend 模板函数 似乎确实遵守新规则共 [temp.inst].
B
的好友不是函数模板。友元声明不是模板声明,所以我们有
[temp.friend] (emphasis mine)
1 A friend of a class or class template can be a function template or class template, a specialization of a function template or class template, or a non-template function or class. For a friend function declaration that is not a template declaration:
if the name of the friend is a qualified or unqualified template-id, the friend declaration refers to a specialization of a function template, otherwise,
if the name of the friend is a qualified-id and a matching non-template function is found in the specified class or namespace, the friend declaration refers to that function, otherwise,
if the name of the friend is a qualified-id and a matching function template is found in the specified class or namespace, the friend declaration refers to the deduced specialization of that function template ([temp.deduct.decl]), otherwise,
the name shall be an unqualified-id that declares (or redeclares) a non-template function.
所以 ffoo
的两个声明没有声明同一个实体。一种是函数模板,另一种是非模板函数。这两个可能存在于与重载相同的声明区域中。
所以这里没有ODR违规。