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