g++ 和 clang++ 与在模板中定义的友元模板函数的不同行为 class
g++ and clang++ different behaviour with friend template function defined inside a template class
C++ 标准专家的另一个 "who's right between g++ and clang++?" 类型的问题。
如下代码
template <int>
struct foo
{
template <typename>
friend void bar ()
{ }
};
int main ()
{
foo<0> f0;
foo<1> f1;
}
使用 clang++ 编译没有问题(只有两个 "unused variable" 警告)但给出以下错误
tmp_002-11,14,gcc,clang.cpp: In instantiation of ‘struct foo<1>’:
tmp_002-11,14,gcc,clang.cpp:27:12: required from here
tmp_002-11,14,gcc,clang.cpp:20:16: error: redefinition of ‘template<class> void bar()’
friend void bar ()
^~~
tmp_002-11,14,gcc,clang.cpp:20:16: note: ‘template<class> void bar()’ previously defined here
使用 g++ 编译。
像往常一样,问题是:谁是对的? g++ 或 clang++ ?
在我的 Debian 平台上使用 clang++ 3.9.1 和 g++ 6.3.0 检查。但是,在 Wandbox 中尝试,似乎与更新的版本相同。
GCC 在这种情况下是正确的。
相关标准写法在[temp.inst]/2:
The implicit instantiation of a class template specialization causes
— the implicit instantiation of the declarations, but not of the
definitions, of the non-deleted class member functions, member
classes, scoped member enumerations, static data members, member
templates, and friends; and
[...]
However, for the purpose of
determining whether an instantiated redeclaration is valid according
to 6.2 and 12.2, a declaration that corresponds to a definition in the
template is considered to be a definition. [ Example: [...]
template<typename T> struct Friendly {
template<typename U> friend int f(U) { return sizeof(T); }
};
Friendly<char> fc;
Friendly<float> ff; // ill-formed: produces second definition of f(U)
— end example ]
与朋友有关的部分由DR2174添加到本段并在C++17中发布(这是一个缺陷报告,因此编译器也应将其应用于以前的标准版本)。
最新版本的 MSVC 和 EDG 在严格模式下也拒绝代码,抱怨重新定义。
[temp.inject]/1有点关系,但只讲友元函数,不谈友元函数模板:
Friend classes or functions can be declared within a class template.
When a template is instantiated, the names of its friends are treated
as if the specialization had been explicitly declared at its point of
instantiation.
C++ 标准专家的另一个 "who's right between g++ and clang++?" 类型的问题。
如下代码
template <int>
struct foo
{
template <typename>
friend void bar ()
{ }
};
int main ()
{
foo<0> f0;
foo<1> f1;
}
使用 clang++ 编译没有问题(只有两个 "unused variable" 警告)但给出以下错误
tmp_002-11,14,gcc,clang.cpp: In instantiation of ‘struct foo<1>’:
tmp_002-11,14,gcc,clang.cpp:27:12: required from here
tmp_002-11,14,gcc,clang.cpp:20:16: error: redefinition of ‘template<class> void bar()’
friend void bar ()
^~~
tmp_002-11,14,gcc,clang.cpp:20:16: note: ‘template<class> void bar()’ previously defined here
使用 g++ 编译。
像往常一样,问题是:谁是对的? g++ 或 clang++ ?
在我的 Debian 平台上使用 clang++ 3.9.1 和 g++ 6.3.0 检查。但是,在 Wandbox 中尝试,似乎与更新的版本相同。
GCC 在这种情况下是正确的。
相关标准写法在[temp.inst]/2:
The implicit instantiation of a class template specialization causes
— the implicit instantiation of the declarations, but not of the definitions, of the non-deleted class member functions, member classes, scoped member enumerations, static data members, member templates, and friends; and
[...]
However, for the purpose of determining whether an instantiated redeclaration is valid according to 6.2 and 12.2, a declaration that corresponds to a definition in the template is considered to be a definition. [ Example: [...]template<typename T> struct Friendly { template<typename U> friend int f(U) { return sizeof(T); } }; Friendly<char> fc; Friendly<float> ff; // ill-formed: produces second definition of f(U)
— end example ]
与朋友有关的部分由DR2174添加到本段并在C++17中发布(这是一个缺陷报告,因此编译器也应将其应用于以前的标准版本)。
最新版本的 MSVC 和 EDG 在严格模式下也拒绝代码,抱怨重新定义。
[temp.inject]/1有点关系,但只讲友元函数,不谈友元函数模板:
Friend classes or functions can be declared within a class template. When a template is instantiated, the names of its friends are treated as if the specialization had been explicitly declared at its point of instantiation.