在 B 类中声明为好友的 A 类成员模板函数无法访问 A 类的私有成员(仅限 Clang)
Class A member template function declared as friend in class B can't access private members of class A (Clang only)
请查看此代码片段。我知道这没有多大意义,它只是为了说明我遇到的问题:
#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'酒吧打印数据和地址(tFo(((;//编译错误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作为一个非模板函数,代码编译时不会出错。
强制编译器在使用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;
}
这似乎是一个编译器提示,因为它看起来很像:
在C++中,为什么';是否可以使用另一个类的模板类型作为模板类成员函数的友元?
更确切地说。。。在bar.PrintDataAndAddress(tFoo());
行中,编译器必须初始化成员函数tBar::PrintDataAndAddress<tFoo>
,同时必须解析友元声明。这是内在的两个独立的步骤。显然,在一个表达式中编写时,编译器不会按正确的顺序执行。为了强制编译器首先通过访问函数指针来实例化bar.PrintDataAndAddress(tFoo())
,这两个步骤的顺序是正确的。
试着在朋友函数之前添加这个
template <typename tFoo>
- 这是关于成员访问规则的正确摘要吗
- 为什么我在空指针错误(链表)中获取成员访问权限
- 成员访问是否在空指针上定义C++?
- C++ IDE 不会推断/自动完成对模板类中的 std::array 下标表达式的成员访问
- 为什么类成员数据必须是静态的才能被模板化类的模板化结构成员访问
- 为什么c++允许成员函数定义中实例的私有成员访问
- C/C++ 包含点的宏参数(成员访问运算符)
- 访问说明符(私有/公共/受保护)如何在内部工作(限制成员访问)?
- 如何将超类的受保护成员访问到其派生类. 如果已在派生类中声明了具有相同名称的函数?
- 内部类私有成员访问和封闭的友好性
- 通过 C++ 中的另一个结构成员访问结构
- 具体化 PRVALUES 成员访问的 decltype 行为不正确
- 常量表达式中的静态成员访问
- XVALUE来自类成员访问表达式
- 未经授权的私有类成员访问会产生编译时错误而不是运行时错误?
- 在 c++ 中,为什么 -> 被称为二进制中缀指针成员访问运算符?
- 如何访问模板参数的成员?“成员访问不完整的类型”
- 不明确的可变参数类成员访问
- C 受保护的成员访问
- 将typeID转换为静态成员访问(C )的命名空间