提问者:小点点

内有ODR断件吗?


下面的代码编译后没有出现任何错误,但它似乎破坏了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规则允许ODR中断为IFNDR(格式不正确,不需要诊断)的情况,所有这些情况似乎都与具有多个翻译单元的程序有关。

第一段非常清楚地说明了单一翻译单位的要求:

[basic.def.odr]/1

任何翻译单元都不得包含任何变量,函数,类类型,枚举类型,模板,参数的默认实参(对于给定作用域中的函数)或默认模板实参的一个以上定义。

上面的代码会打破ODR吗? 如果是这样,在单个翻译单元中破坏ODR是否需要编译器诊断?

*注意:代码示例中的friend模板函数似乎符合[temp.inst]的新规则。


共1个答案

匿名用户

b的友元不是函数模板。 这个朋友声明不是模板声明,所以我们有

[Temp.Friend](强调我的)

1类或类模板的朋友可以是函数模板或类模板,函数模板或类模板的专门化,也可以是非模板函数或类。 对于不是模板声明的友元函数声明:

>

  • 如果友元的名称是限定的或非限定的模板ID,则友元声明引用函数模板的专门化,否则,

    如果友元的名称是限定ID,并且在指定的类或命名空间中找到匹配的非模板函数,则友元声明引用该函数,否则,

    如果friend的名称是限定ID,并且在指定的类或命名空间中找到匹配的函数模板,则friend声明引用该函数模板的推导专门化([temp.dedt.decl]),否则,

    名称应为声明(或重新声明)非模板函数的不合格的-ID。

    因此ffoo的两个声明并不声明同一个实体。 一个是函数模板,另一个是非模板函数。 这两个可能与重载存在于同一个声明性区域中。

    所以这里没有违反ODR。