Reputation: 705
I have the following sample code, reduced to the essential, that compiles with gcc 6.1, gcc 7.0 head and Visual Studio 2015/2017RC, but not with any clang version.
#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 tells me: prog.cc:12:34: error: '_p' is a private member of 'outer::foo' return std::make_tuple(c._p...);
I don't understand why clang does not recognize the friend declaration. Is this a bug of clang or is it a problem of all the other compilers?
When I make foo a non template class, clang does not complain. Any ideas for a workaround?
Many thanks in advance
Upvotes: 12
Views: 357
Reputation: 13988
As the "why?" question was deeply discussed in this thread I will focus only on a possible workaround. You could try to wrap your function into a dummy struct just to ensure all the possible overloads of it are also included in a friend-list of your foo
. The workaround proposition could look as follows:
#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;
}
Upvotes: 1
Reputation: 66200
It seems to me a clang++ bug (it's true that _p
is private
, but bar_()
should be a friend
function for foo
class).
A workaround could be add a getter getP()
in foo
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; }
};
and use it in bar_()
template <typename A, typename B, typename...C>
auto bar_(A&&, B&&, C&&... c) {
return std::make_tuple(c.getP()...);
}
Upvotes: 1