class 模板名称中的隐藏好友与内联命名空间中的另一个符号冲突
hidden friend in a class template name clashes with another symbol in inline namespace
我想为我的类型提供一个隐藏的好友,同时在内联命名空间中还有另一个同名对象。对于普通类型一切正常。
但是如果我有模板,当我实例化模板时编译器会出错
redefinition of 'cpo' as different kind of symbol
代码如下:
namespace lib{
struct CPO{
template<typename... T>
constexpr decltype(auto) operator()(T&&... args) const{
cpo(static_cast<T&&>(args)...);
}
};
inline namespace cpo_impl_{
inline constexpr CPO cpo{};
}
struct Foo1{
friend auto cpo(Foo1){
return 5;
}
};
template <typename T>
struct Foo2{
friend auto cpo(Foo2){
return 6;
}
};
}
int main(){
lib::Foo1 f1{};
lib::cpo(f1); // works fine;
lib::Foo2<int> f2{}; // error here
}
较小的例子在这里
namespace lib{
inline namespace impl_{
inline constexpr int foo = 5;
}
template <typename T>
struct Bar{
friend auto foo(Bar){
return 4;
}
};
}
int main(){
lib::bar<int> b{};
}
顺便说一句,我知道其他技术,例如 tag_invoke
但在这里我无法控制名称和库
您的密码是 well-formed。这是Clang Bug 37556.
Compiling this well-formed program with -std=c++2a:
namespace X {
inline namespace Y { int swap; }
template<class>
struct S {
friend void swap(S&, S&) {}
};
}
int main() {
X::S<int> s1, s2;
swap(s1, s2);
}
produces diagnostics (https://godbolt.org/g/ceWLxY):
<source>:6:21: error: redefinition of 'swap' as different kind of symbol
friend void swap(S&, S&) {}
^
<source>:11:15: note: in instantiation of template class 'X::S<int>' requested here
X::S<int> s1, s2;
^
<source>:2:30: note: previous definition is here
inline namespace Y { int swap; }
^
1 error generated.
Note that the program compiles successfully if S is replaced by a
non-template class. Discussion on the CWG reflector verified that this
program is well-formed, including Richard's statement "Oops, Clang's
redeclaration check in the template instantiation case is incorrectly
performing a redeclaration lookup as if for a qualified name here,
rather than a redeclaration lookup for an unqualified name."
但是没有修复的时间表。
作为解决方法,您可以将 Foo2
包装在它自己的 inline namespace
中
inline namespace disambig_detail {
template <typename T>
struct Foo2{
friend auto cpo(Foo2){
return 6;
}
};
}
这应该足以改变声明区域以避免 mis-diagnosis。同时,名称查找的过程应该与命名空间不存在时的过程几乎相同。
我想为我的类型提供一个隐藏的好友,同时在内联命名空间中还有另一个同名对象。对于普通类型一切正常。
但是如果我有模板,当我实例化模板时编译器会出错
redefinition of 'cpo' as different kind of symbol
代码如下:
namespace lib{
struct CPO{
template<typename... T>
constexpr decltype(auto) operator()(T&&... args) const{
cpo(static_cast<T&&>(args)...);
}
};
inline namespace cpo_impl_{
inline constexpr CPO cpo{};
}
struct Foo1{
friend auto cpo(Foo1){
return 5;
}
};
template <typename T>
struct Foo2{
friend auto cpo(Foo2){
return 6;
}
};
}
int main(){
lib::Foo1 f1{};
lib::cpo(f1); // works fine;
lib::Foo2<int> f2{}; // error here
}
较小的例子在这里
namespace lib{
inline namespace impl_{
inline constexpr int foo = 5;
}
template <typename T>
struct Bar{
friend auto foo(Bar){
return 4;
}
};
}
int main(){
lib::bar<int> b{};
}
顺便说一句,我知道其他技术,例如 tag_invoke
但在这里我无法控制名称和库
您的密码是 well-formed。这是Clang Bug 37556.
Compiling this well-formed program with -std=c++2a:
namespace X { inline namespace Y { int swap; } template<class> struct S { friend void swap(S&, S&) {} }; } int main() { X::S<int> s1, s2; swap(s1, s2); }
produces diagnostics (https://godbolt.org/g/ceWLxY):
<source>:6:21: error: redefinition of 'swap' as different kind of symbol friend void swap(S&, S&) {} ^ <source>:11:15: note: in instantiation of template class 'X::S<int>' requested here X::S<int> s1, s2; ^ <source>:2:30: note: previous definition is here inline namespace Y { int swap; } ^ 1 error generated.
Note that the program compiles successfully if S is replaced by a non-template class. Discussion on the CWG reflector verified that this program is well-formed, including Richard's statement "Oops, Clang's redeclaration check in the template instantiation case is incorrectly performing a redeclaration lookup as if for a qualified name here, rather than a redeclaration lookup for an unqualified name."
但是没有修复的时间表。
作为解决方法,您可以将 Foo2
包装在它自己的 inline namespace
inline namespace disambig_detail {
template <typename T>
struct Foo2{
friend auto cpo(Foo2){
return 6;
}
};
}
这应该足以改变声明区域以避免 mis-diagnosis。同时,名称查找的过程应该与命名空间不存在时的过程几乎相同。