在类模板的其他未定义成员类的显式特化中定义隐藏朋友是否合法?

dfr*_*fri 5 c++ templates friend template-specialization language-lawyer

根据[temp.expl.spec]合法放置显式专的规则并不完全容易掌握,尤其是在与隐藏的朋友混合时,以避免我的专的自焚[temp.expl.spec]/8和友元函数 我希望对以下内容有第二意见(1)

  • 在类模板的头文件中,在类模板的其他未定义(/仅声明)成员类的显式特化中定义隐藏朋友是否合法?假设该报头包含在至少两个不同的翻译单元中。

(1)根据以下标准参考资料,我自己对标准的解释是“是的;这是合法的”。


或者,举个例子:下面的程序格式正确吗?

// s.h
#pragma once

template <int N>
struct S {
    struct M;
};
      
template<>
struct S<42>::M {
    friend int f(M) { return 42; }
};

// foo.h
#pragma once
void foo();

// foo.cpp
#include "foo.h"
#include <iostream>
#include "s.h"

void foo() {
    std::cout << f(S<42>::M{});
}

// main.cpp
#include <iostream>
#include "foo.h"
#include "s.h"

int main() {
    std::cout << f(S<42>::M{});
    foo();
}
Run Code Online (Sandbox Code Playgroud)

请注意,根据[class.friend]/7定义在其朋友声明中定义的朋友是内联的,因此虽然我有点担心 ODR 违规,但它不是针对朋友,而是针对成员类专业化。我认为 [basic.def.odr]/6在这里适用,如果我们认为S<42>::M“只是”一个类类型。


Clang 和 GCC 都接受上述内容,但如果程序格式不正确或具有未定义的行为,这可能并不重要。GCC 10.1.0 演示Clang 10.0.0 演示

Dav*_*ing 1

是的,模板类(包括类模板和类模板的成员类)的显式特化是一个类,因此在通常情况下允许多个定义。这些定义被视为程序中只有一个f,因此也可以。(它\xe2\x80\x99s不清楚implicitinline在这里做了什么,因为只有一个定义,f在某种程度上,作为一个整体只有一个S<42>::M。)缺乏定义S<N>::M在这里也没有任何意义; 像这样的 \xe2\x80\x9cmember 显式特化\xe2\x80\x9d 实际上是封闭类模板的缩写特化S,所以S<42>::M完全不相关。

\n