在 class 模板的 non-defined 成员 class 的显式特化中定义隐藏好友是否合法?

Is it legal to define a hidden friend in an explicit specialization of an otherwise non-defined member class of a class template?

根据 [temp.expl.spec] are not entirely easy to grasp, particularly when mixing with hidden friends, so as to avoid the immolation[temp.expl.spec]/8 我的专业化和友元函数的显式专业化的合法放置规则 我希望获得第二意见(1)以下:

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


或者,举个例子:下面的程序是well-formed?

// 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();
}

请注意,如果我们将 S<42>::M 视为“只是”一个 class 类型,则根据 [class.friend]/7, so whilst I'm somewhat worried about ODR-violations it is not for the friend but rather for the member class specialization. I think [basic.def.odr]/6 在其好友声明中定义的好友是内联的。


Clang 和 GCC 都接受上述内容,但如果程序是 ill-formed NDR 或具有未定义的行为,这可能并不重要。 GCC 10.1.0 DEMO, Clang 10.0.0 DEMO.

是的,模板化 class(包括 class 模板和 class 模板的成员 classes)的显式特化是 class , 因此在通常情况下允许多个定义。这些定义被视为程序中只有 one,因此 f 也可以。 (不清楚 implicit inline 在这里做了什么,因为 f 只有一个定义,以至于整个 S<42>::M 只有一个。) S<N>::M 的定义在这里意味着什么;像这样的“成员显式特化”实际上是 enclosingclass 模板 S 的缩写特化,因此 S<42>::M 完全不相关。