请查看此代码段 . 我知道它没有多大意义,它只是为了说明我遇到的问题:
#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:错误:'PrintAddress'是'tBar'PrintAddress(thing)的私有成员; source_file.cpp:42:6:注意:在实例化函数模板>特殊化'tBar :: PrintDataAndAddress'这里请求bar.PrintDataAndAddress(tFoo()); //编译错误source_file.cpp:17:7:注意:声明私有这里void PrintAddress(const T&thing)
但只有在Clang . GCC和MSVC都可以(你可以通过在http://rextester.com/l/cpp_online_compiler_clang中粘贴代码来快速测试)
似乎 tBar::PrintDataAndAddress<tFoo>(const tFoo&)
使用与 tFoo
相同的访问权限,在那里它是友好的 . 我知道这是因为在 tBar
中与 tFoo
交朋友修复了这个问题 . 如果 tBar::PrintDataAndAddress
是非模板函数,问题也会消失 .
我无法在标准中找到解释此行为的任何内容 . 我相信这可能是对14.6.5 - temp.inject的错误解释,但我无法声称我已经阅读了所有内容 .
有没有人知道Clang是否正确无法编译上述代码?如果是这样的话,你能否引用相关的C标准文本?
似乎要发生这个问题,被访问的私有成员需要是模板功能 . 例如,在上面的例子中,如果我们使PrintAddress成为非模板函数,代码将编译而没有错误 .
2 回答
在使用之前强制编译器实例化
tBar::PrintDataAndAddress<tFoo>
解决了问题 .它似乎是一个编译器promlem,因为它看起来非常相似:
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>
,同时它必须解析好友声明 . 这是两个单独的步骤 . 显然,当编写一个表达式时,编译器不会按照严格顺序执行此操作 . 要强制编译器首先通过访问函数指针来实例化bar.PrintDataAndAddress(tFoo())
,这两个步骤的顺序正确 .尝试在友元功能之前添加此功能