【发布时间】:2015-12-29 14:53:37
【问题描述】:
对不起,这个问题的标题太复杂了;我试图描述我为这个问题构建的最小 SSCCE。
我有以下代码:
#include <iostream>
namespace fizz
{
template<typename... Ts>
class bar
{
public:
template<int I, typename... Us>
friend auto foo(const bar<Us...> &);
private:
int i = 123;
};
template<int I, typename... Ts>
auto foo(const bar<Ts...> & b)
{
return b.i;
}
}
int main()
{
std::cout << fizz::foo<1>(fizz::bar<int, float>{});
}
此代码compiles with GCC 5.2 和doesn't with Clang 3.7:
main.cpp:19:18: error: 'i' is a private member of 'fizz::bar<int, float>'
return b.i;
^
main.cpp:25:24: note: in instantiation of function template specialization 'fizz::foo<1, int, float>' requested here
std::cout << fizz::foo<1>(fizz::bar<int, float>{});
^
main.cpp:13:13: note: declared private here
int i = 123;
^
但是,如果您稍微更改代码(尽管以某种方式对我来说并不完全有用,因为在实际代码中这会引入大量样板文件):
#include <iostream>
namespace fizz
{
template<typename... Ts>
class bar
{
public:
template<int I, typename... Us>
friend int foo(const bar<Us...> &);
private:
int i = 123;
};
template<int I, typename... Ts>
int foo(const bar<Ts...> & b)
{
return b.i;
}
}
int main()
{
std::cout << fizz::foo<1>(fizz::bar<int, float>{});
}
不同的是,在不使用 Clang 编译的代码版本中,友元函数模板使用 C++14 的 auto 返回类型推导,而工作的则明确表示返回 int。 auto 返回类型推导的其他变体也会出现同样的问题,例如 auto && 或 const auto &。
哪个编译器是正确的?请提供一些标准引用来支持答案,因为很有可能需要为一个(......希望不是两个)编译器提交一个错误......或者一个标准缺陷,如果两者都是正确的(这不会'不是第一次)。
【问题讨论】:
-
我很惊讶。我认为类中的朋友函数与外部函数无关,而无需在朋友之前声明类之外的函数。然而,情况似乎并非如此。唔。在实践中,
->decltype是否可行? -
@Yakk A
friend声明可以在最里面的封闭命名空间中声明一个函数。我不认为auto在这里有什么特别之处,并怀疑这是一个clang 错误,但无法想出一套好的措辞来支持这一点。 -
如果你删除了
int I模板参数,并对foo()进行了不合格的调用,clang 会将调用报告为模棱两可......所以出于某种原因它确实认为有两个单独的函数模板foos. -
我认为它引入了它,但出于某种原因认为它会有所不同,除非首先引入“外部”。我不知道为什么我会这么想。
-
啊哈!因为内联定义友元确实遵循该规则: [class.friend]/7 -- 非内联友元函数位于封闭命名空间的词法范围内。 (这就是我产生这种误解的原因)
标签: c++ templates language-lawyer c++14 friend