Почему clang отвергает переменную функцию имени шаблона
У меня есть следующий пример кода, сведенный к существенному, который компилируется с 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: error: '_p' является частным членом 'outer:: foo' return std:: make_tuple (c._p...);
Я не понимаю, почему clang не распознает объявление друга. Является ли это ошибкой clang или это проблема всех других компиляторов?
Когда я делаю foo классом без шаблона, clang не жалуется.
Любые идеи для обхода?
Большое спасибо заранее
Ответы
Ответ 1
Как "почему?" вопрос был глубоко обсужден в этой теме Я сосредоточусь только на возможном обходном пути. Вы можете попытаться объединить вашу функцию в фиктивную структуру, чтобы гарантировать, что все возможные перегрузки ее также включены в список друзей вашего 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;
}
[live demo]
Ответ 2
Мне кажется, что ошибка clang++ (это правда, что _p
есть private
, но bar_()
должна быть функцией friend
для класса foo
).
Обходной путь может быть добавлен getter getP()
в 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; }
};
и использовать его в bar_()
template <typename A, typename B, typename...C>
auto bar_(A&&, B&&, C&&... c) {
return std::make_tuple(c.getP()...);
}