为什么clang拒绝variadic模板的朋友功能

时间:2016-11-21 16:27:23

标签: c++ templates c++14 variadic-templates 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;
}
克朗告诉我: prog.cc:12:34:错误:&#39; _p&#39;是&lt;外部:: foo&#39;的私人成员         return std :: make_tuple(c._p ...);

我不明白为什么clang不承认朋友的声明。这是一个铿锵的错误还是所有其他编译器的问题?

当我使foo成为非模板类​​时,clang不会抱怨。 任何解决方法的想法?

非常感谢提前

2 个答案:

答案 0 :(得分:1)

在我看来是一个clang ++ bug(_pprivate是真的,但bar_()应该是friend foo函数getP() } class)。

解决方法是在foo

中添加一个getter 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()...); }

中使用它
{{1}}

答案 1 :(得分:1)

作为“为什么?”问题在this thread深入讨论过。我将只关注可能的解决方法。您可以尝试将函数包装到虚拟结构中,以确保它的所有可能重载也包含在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]