为什么 clang 拒绝可变模板友元函数
Why clang rejects variadic template friend function
我有以下示例代码,精简到基本,使用 gcc 6.1、gcc 7.0 head 和 Visual Studio 2015/2017RC 编译,但不使用任何 clang 版本。
#include <iostream>
#include <tuple>
using namespace std;
namespace outer {
namespace test {
template <typename A, typename B, typename...C>
auto bar_(A&&, B&&, C&&... c) {
return std::make_tuple(c._p...);
}
}
template <typename A, typename B, typename...C>
auto bar(A a, B b, C&&... c) {
return test::bar_(std::move(a), std::move(b), std::forward<C>(c)...);
}
template<typename T>
class foo
{
template <typename A, typename B, typename...C>
friend auto test::bar_(A&&, B&&, C&&... c);
int _p;
public:
foo(int f) : _p(f) {}
};
}
int main() {
outer::foo<int> a1(1);
outer::foo<int> a2(2);
auto result = outer::bar(2.3, 4.5, a1, a2);
cout << get<0>(result) << " " << get<1>(result) << '\n';
return 0;
}
clang 告诉我:
prog.cc:12:34: 错误:'_p' 是 'outer::foo' 的私有成员
return std::make_tuple(c._p...);
我不明白为什么 clang 不识别友元声明。这是 clang 的错误还是所有其他编译器的问题?
当我将 foo 设为非模板时 class,clang 不会报错。
有解决方法的想法吗?
非常感谢
在我看来是一个 clang++ 错误(_p
是 private
是真的,但是 bar_()
应该是 foo
的 friend
函数 class).
解决方法是在 foo
中添加 getter getP()
template<typename T>
class foo
{
// template <typename A, typename B, typename...C>
// friend auto outer::test::bar_(A&&, B&&, C&&... c);
int _p;
public:
foo(int f) : _p(f) {}
int getP () const // <--- added getP()
{ return _p; }
};
并在bar_()
中使用它
template <typename A, typename B, typename...C>
auto bar_(A&&, B&&, C&&... c) {
return std::make_tuple(c.getP()...);
}
由于 "why?" 问题在 中进行了深入讨论,因此我将只关注可能的解决方法。您可以尝试将您的函数包装到一个虚拟结构中,以确保它的所有可能重载也包含在您的 foo
的好友列表中。变通方案可能如下所示:
#include <iostream>
#include <tuple>
using namespace std;
namespace outer {
namespace test {
struct wrapper{
template <typename A, typename B, typename...C>
static auto bar_(A&&, B&&, C&&... c) {
return std::make_tuple(c._p...);
}
};
}
template <typename A, typename B, typename...C>
auto bar(A a, B b, C&&... c) {
return test::wrapper::bar_(std::move(a), std::move(b), std::forward<C>(c)...);
}
template<typename T>
class foo
{
friend struct test::wrapper;
int _p;
public:
foo(int f) : _p(f) {}
};
}
int main() {
outer::foo<int> a1(1);
outer::foo<int> a2(2);
auto result = outer::bar(2.3, 4.5, a1, a2);
cout << get<0>(result) << " " << get<1>(result) << '\n';
return 0;
}
我有以下示例代码,精简到基本,使用 gcc 6.1、gcc 7.0 head 和 Visual Studio 2015/2017RC 编译,但不使用任何 clang 版本。
#include <iostream>
#include <tuple>
using namespace std;
namespace outer {
namespace test {
template <typename A, typename B, typename...C>
auto bar_(A&&, B&&, C&&... c) {
return std::make_tuple(c._p...);
}
}
template <typename A, typename B, typename...C>
auto bar(A a, B b, C&&... c) {
return test::bar_(std::move(a), std::move(b), std::forward<C>(c)...);
}
template<typename T>
class foo
{
template <typename A, typename B, typename...C>
friend auto test::bar_(A&&, B&&, C&&... c);
int _p;
public:
foo(int f) : _p(f) {}
};
}
int main() {
outer::foo<int> a1(1);
outer::foo<int> a2(2);
auto result = outer::bar(2.3, 4.5, a1, a2);
cout << get<0>(result) << " " << get<1>(result) << '\n';
return 0;
}
clang 告诉我: prog.cc:12:34: 错误:'_p' 是 'outer::foo' 的私有成员 return std::make_tuple(c._p...);
我不明白为什么 clang 不识别友元声明。这是 clang 的错误还是所有其他编译器的问题?
当我将 foo 设为非模板时 class,clang 不会报错。 有解决方法的想法吗?
非常感谢
在我看来是一个 clang++ 错误(_p
是 private
是真的,但是 bar_()
应该是 foo
的 friend
函数 class).
解决方法是在 foo
getP()
template<typename T>
class foo
{
// template <typename A, typename B, typename...C>
// friend auto outer::test::bar_(A&&, B&&, C&&... c);
int _p;
public:
foo(int f) : _p(f) {}
int getP () const // <--- added getP()
{ return _p; }
};
并在bar_()
template <typename A, typename B, typename...C>
auto bar_(A&&, B&&, C&&... c) {
return std::make_tuple(c.getP()...);
}
由于 "why?" 问题在 foo
的好友列表中。变通方案可能如下所示:
#include <iostream>
#include <tuple>
using namespace std;
namespace outer {
namespace test {
struct wrapper{
template <typename A, typename B, typename...C>
static auto bar_(A&&, B&&, C&&... c) {
return std::make_tuple(c._p...);
}
};
}
template <typename A, typename B, typename...C>
auto bar(A a, B b, C&&... c) {
return test::wrapper::bar_(std::move(a), std::move(b), std::forward<C>(c)...);
}
template<typename T>
class foo
{
friend struct test::wrapper;
int _p;
public:
foo(int f) : _p(f) {}
};
}
int main() {
outer::foo<int> a1(1);
outer::foo<int> a2(2);
auto result = outer::bar(2.3, 4.5, a1, a2);
cout << get<0>(result) << " " << get<1>(result) << '\n';
return 0;
}