【发布时间】:2017-03-14 00:24:36
【问题描述】:
请看一下这段代码 sn-p。我知道这没有多大意义,只是为了说明我遇到的问题:
#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' 的私有成员 打印地址(事物); source_file.cpp:42:6: 注意:在函数模板的实例化中 >specialization 'tBar::PrintDataAndAddress' 在此处请求 bar.PrintDataAndAddress(tFoo()); // 编译错误 source_file.cpp:17:7: 注意:这里声明为私有 void PrintAddress(const T& 事物)
但仅在 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 设为非模板函数,代码将编译不会出错。
【问题讨论】:
-
也许我遗漏了一些东西,但在我看来,clang 不编译这个是完全明智的。我觉得奇怪的是,朋友声明被注释掉了,导致它编译。在我看来,无论如何它都不应该编译。过去我遇到过很多情况,其中 gcc 在涉及大量模板的友谊方面存在“过于宽松”的错误,我认为就是这种情况。
-
@NirFriedman 为什么你认为 Clang 不编译它是明智的?这对我来说似乎违反直觉。 A 类允许朋友访问 B 类成员函数(在本例中为模板函数),因此它可以访问 A 的私有和受保护成员,但为什么会删除对 B 的私有/受保护成员的访问?
-
对我来说看起来像一个铿锵虫。正在搜索以查看是否已被举报。
-
主干上仍然中断。报告为llvm.org/bugs/show_bug.cgi?id=30859,略短版本的@aschepler 的repro。
标签: c++ c++11 templates clang++