c++ - 在 B 类中声明为友元的 A 类成员模板函数无法访问 A 类的私有(private)成员(仅限 Clang)

标签 c++ c++11 templates clang++

请查看此代码段。我知道这没有多大意义,只是为了说明我遇到的问题:

#include <iostream>
using namespace std;

struct tBar
{
    template <typename T>
    void PrintDataAndAddress(const T& thing)
    {
        cout << thing.mData;
        PrintAddress<T>(thing);
    }

private:
    // friend struct tFoo; // fixes the compilation error

    template <typename T>
    void PrintAddress(const T& thing)
    {
        cout << " - " << &thing << endl;
    }
};

struct tFoo
{
    friend void tBar::PrintDataAndAddress<tFoo>(const tFoo&);
    private:

    int mData = 42;
};

struct tWidget
{
    int mData = 666;
};

int main() 
{
    tBar bar;
    bar.PrintDataAndAddress(tWidget()); // Fine

    bar.PrintDataAndAddress(tFoo()); // Compilation error

    return 0;
}

以上代码触发如下错误:

source_file.cpp:10:3: error: 'PrintAddress' is a private member of 'tBar' PrintAddress(thing); source_file.cpp:42:6: note: in instantiation of function template >specialization 'tBar::PrintDataAndAddress' requested here bar.PrintDataAndAddress(tFoo()); // Compilation error source_file.cpp:17:7: note: declared private here void PrintAddress(const T& thing)

但仅在 Clang++ 中。 GCC 和 MSVC 都可以(你可以通过将代码粘贴到 http://rextester.com/l/cpp_online_compiler_clang 中来快速测试)

似乎 tBar::PrintDataAndAddress<tFoo>(const tFoo&) 使用与 tFoo 相同的访问权限,在那里它是 friend 。我知道这一点,因为在 tFoo 中与 tBar 成为 friend 可以解决此问题。如果 tBar::PrintDataAndAddress 是非模板函数,问题也会消失。

我无法在标准中找到任何解释此行为的内容。我认为这可能是对 14.6.5 - temp.inject 的错误解释,但我不能声称我已经阅读了所有内容。

有谁知道 Clang 未能编译上述代码是否正确?如果是这样,您能否引用相关的 C++ 标准文本?

似乎要发生这个问题,被访问的私有(private)成员需要是一个模板函数。例如,在上面的例子中,如果 我们将 PrintAddress 设为非模板函数,代码将编译不会出错。

最佳答案

强制编译器实例化 tBar::PrintDataAndAddress<tFoo>在使用它之前解决问题。

int main() 
{
    tBar bar;
    bar.PrintDataAndAddress(tWidget()); // Fine

    auto x = &tBar::PrintDataAndAddress<tFoo>; // <= make it work....

    bar.PrintDataAndAddress(tFoo()); // Now fine

   return 0;
}

这似乎是一个编译器问题,因为它看起来与此非常相似:

In C++, why isn't it possible to friend a template class member function using the template type of another class?

更准确一点...在 bar.PrintDataAndAddress(tFoo()); 行中编译器必须实例化成员函数 tBar::PrintDataAndAddress<tFoo>同时它必须解决 friend 声明。那是内部两个单独的步骤。显然,当用一个表达式编写时,编译器并没有按照严格的顺序执行此操作。强制编译器实例化 bar.PrintDataAndAddress(tFoo())首先通过访问函数指针这两个步骤的顺序是正确的。

关于c++ - 在 B 类中声明为友元的 A 类成员模板函数无法访问 A 类的私有(private)成员(仅限 Clang),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40350327/

相关文章:

templates - Play 框架的 Scala 模板中的动态参数

c++ - 自记录类型别名(typedef)以指示它将在另一个特定类中使用

c++ - int (*p) 和 int *p 有区别吗?

c++ - 为什么结构体的 sizeof 不等于每个成员的 sizeof 之和?

c++ - C++ 中的 sqldriverconnect 无法连接到本地数据库 sql 2008

c++ - 结构类似于优先级队列,但具有类似下限的结构

c++ - 在 C++ 中创建大小为 1000000000 的数组给了我以下错误。请帮助我理解并解决它

c++ - 在被调用函数中更改函数指针(std::function)是否安全?

c++ - 如何以更好的性能传递和共享 shared_ptr 所有权?

c++ - Visual Studio 中的模板化函数指针数组