朋友、私有函数、模板别名和decltype......clang拒绝这种情况是否正确?

问题描述 投票:5回答:1

在下面的代码中(螺栓连接):

#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 的功能 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{};
            ^

我本来以为访问是没有问题的,因为模板别名是在友类中声明的。

然而,根据我的经验,在解释C++标准时,Clang通常是正确的(比gcc更正确)。

Clang拒绝这段代码是否正确? 如果是的话,我漏掉了什么?

注:gcc 7.x、8.x、9.x都接受这段代码。

c++ language-lawyer friend
1个回答
4
投票

这就是 窃听器 在Clang。每 [class.friend]2:

声明一个类是朋友,意味着可以在被结交的类的基础规范和成员声明中访问授予友谊的类的私有成员和受保护成员的名称。

[class.mem], a 模板-声明 可以是 成员声明和每 [temp.pre]2.5 an 别名声明 可以是 声明 在...中 模板-声明. 所以,一个成员别名模板可以访问该类朋友的私有成员和受保护成员。

幸运的是,这个错误似乎只适用于类的 定义型标识别名声明你可以通过将计算移到一个辅助类中来解决这个问题(有嵌套的 type 别名),或者更简明地说是对一个叫 "小白兔 "的人来说。默认模板-参数:

template <typename T, class U = decltype(std::declval<T>().function())>
using IndirectResult = U;
© www.soinside.com 2019 - 2024. All rights reserved.