问题描述
在以下代码中( godbolt链接):
#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
试图访问的
: private
函数内部
Clang is perfectly happy with the use of DirectResult
, but will complaing that IndirectResult
is attempting to access a private
function of Inner
:
<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{};
^
由于模板别名是在好友类中声明的,因此我希望可以很好地进行访问.
I would have expected the access to be fine, as the template alias is declared within the friend class.
但是,以我的经验,在解释C ++标准时,Clang通常是正确的(比gcc更重要).
However, in my experience Clang is generally right (more so than gcc) when it comes to interpreting the C++ standard.
Clang拒绝此代码是否正确?如果是,我还缺少什么?
Is Clang correct in rejecting this code? And if so, what am I missing?
注意:gcc 7.x,8.x和9.x接受代码.
推荐答案
这是 abug .每个 [class.friend]/2 :
This is a bug in Clang. Per [class.friend]/2:
每个> [class.mem] ,模板声明可以是成员声明,并且每个 [temp.pre]/2.5 ,别名声明可以是模板声明.因此,成员别名模板可以访问该类朋友的私有成员和受保护成员.
Per [class.mem], a template-declaration can be a member-declaration, and per [temp.pre]/2.5 an alias-declaration can be the declaration in a template-declaration. So a member alias template has access to the private and protected members of the class's friends.
幸运的是,该错误似乎仅适用于 alias-declaration 的 defining-type-id ;您可以通过将计算移到帮助程序类(具有嵌套的 type
别名)中或更简单地将其移至默认模板参数 来解决此问题:
Fortunately, the bug appears only to apply to the defining-type-id of an alias-declaration; you can work around it by moving the computation into a helper class (with nested type
alias), or more concisely to a default template-argument:
template <typename T, class U = decltype(std::declval<T>().function())>
using IndirectResult = U;
这篇关于朋友,私有函数,模板别名和decltype ...用clang拒绝是正确的吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!