朋友、私有函数、模板别名和 decltype ... clang 拒绝这个是正确的吗?
Friend, private function, template alias, and decltype... is clang correct in rejecting this?
在下面的代码中(godbolt link):
#include <utility>
struct Friend {
class Inner {
friend struct Friend;
int function() { return 0; }
};
using DirectResult = decltype(std::declval<Inner>().function());
template <typename T>
using IndirectResult = decltype(std::declval<T>().function());
};
int main() {
Friend::DirectResult direct{};
Friend::IndirectResult<Friend::Inner> indirect{};
return direct + indirect;
}
Clang 对 DirectResult
的使用非常满意,但会抱怨 IndirectResult
正在尝试访问 Inner
的 private
函数:
<source>:13:55: error: 'function' is a private member of 'Friend::Inner'
using IndirectResult = decltype(std::declval<T>().function());
^
<source>:18:13: note: in instantiation of template type alias 'IndirectResult' requested here
Friend::IndirectResult<Friend::Inner> indirect{};
^
我原以为访问会很好,因为模板别名是在朋友 class 中声明的。
但是,根据我的经验,在解释 C++ 标准时,Clang 通常是正确的(比 gcc 更正确)。
Clang 拒绝此代码是否正确?如果是,我错过了什么?
注意:gcc 7.x、8.x 和 9.x 接受代码。
这是a bug in Clang. Per [class.friend]/2:
Declaring a class to be a friend implies that the names of private and protected members from the class granting friendship can be accessed in the base-specifiers and member declarations of the befriended class.
根据[class.mem], a template-declaration can be a member-declaration, and per [temp.pre]/2.5,别名声明可以是模板声明声明。因此,成员别名模板可以访问 class 朋友的私有和受保护成员。
幸运的是,该错误似乎仅适用于 别名声明 的 defining-type-id;您可以通过将计算移动到助手 class(具有嵌套的 type
别名)或更简洁地移动到 默认模板参数 :
template <typename T, class U = decltype(std::declval<T>().function())>
using IndirectResult = U;
在下面的代码中(godbolt link):
#include <utility>
struct Friend {
class Inner {
friend struct Friend;
int function() { return 0; }
};
using DirectResult = decltype(std::declval<Inner>().function());
template <typename T>
using IndirectResult = decltype(std::declval<T>().function());
};
int main() {
Friend::DirectResult direct{};
Friend::IndirectResult<Friend::Inner> indirect{};
return direct + indirect;
}
Clang 对 DirectResult
的使用非常满意,但会抱怨 IndirectResult
正在尝试访问 Inner
的 private
函数:
<source>:13:55: error: 'function' is a private member of 'Friend::Inner'
using IndirectResult = decltype(std::declval<T>().function());
^
<source>:18:13: note: in instantiation of template type alias 'IndirectResult' requested here
Friend::IndirectResult<Friend::Inner> indirect{};
^
我原以为访问会很好,因为模板别名是在朋友 class 中声明的。
但是,根据我的经验,在解释 C++ 标准时,Clang 通常是正确的(比 gcc 更正确)。
Clang 拒绝此代码是否正确?如果是,我错过了什么?
注意:gcc 7.x、8.x 和 9.x 接受代码。
这是a bug in Clang. Per [class.friend]/2:
Declaring a class to be a friend implies that the names of private and protected members from the class granting friendship can be accessed in the base-specifiers and member declarations of the befriended class.
根据[class.mem], a template-declaration can be a member-declaration, and per [temp.pre]/2.5,别名声明可以是模板声明声明。因此,成员别名模板可以访问 class 朋友的私有和受保护成员。
幸运的是,该错误似乎仅适用于 别名声明 的 defining-type-id;您可以通过将计算移动到助手 class(具有嵌套的 type
别名)或更简洁地移动到 默认模板参数 :
template <typename T, class U = decltype(std::declval<T>().function())>
using IndirectResult = U;