2016-11-21 6 views
12

以下のサンプルコードをgcc 6.1、gcc 7.0ヘッド、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:エラー: '_p' 'は、外側:: foo' で リターンのstd :: make_tuple(c._p ...)の民間メンバーであります;

なぜclangが友人宣言を認識しないのかわかりません。これはclangのバグですか、それとも他のすべてのコンパイラの問題ですか?

fooをテンプレート以外のクラスにすると、clangは文句を言わない。 回避策の候補はありますか?事前

+3

ていません[この](http://stackoverflow.com/questions/32889492/friend-function-template-with-automatic-return-タイプ控除 - あなたの質問に答えてもらえませんか? –

+1

回避策として、 'friend auto test :: bar_(A &&、B &&、C && ... c) - > decltype(std :: make_tuple(c._p ...));'を友人として使うこともできます'bar_'として)関数シグネチャを返します。 [ライブデモ](http://melpon.org/wandbox/permlink/CEBDjgZGGLbAtWY1) –

+0

私はvariadicとfriendの組み合わせを探しました。しかし、私は自動車が問題であることを認識していませんでした。はい、問題はありますか、戻り値の型を明示的に指定すると問題が解決しました。実際の戻り値の型ははるかに複雑なので、試していませんでした。どうもありがとう! –

答えて

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]

1

多くのおかげでそれが打ち鳴らす++のバグ(それは_pprivateであることは事実だが、bar_()fooクラスのfriend関数であるべき)私には思えます。

この問題を回避するには、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; } 
}; 

にゲッターgetP()を追加し、 "なぜ?" としてbar_()

template <typename A, typename B, typename...C> 
auto bar_(A&&, B&&, C&&... c) { 
    return std::make_tuple(c.getP()...); 
} 
+0

お返事ありがとうございます。しかし、_pは私が公開したくない単純な例でした。上で述べたように、回避策は戻り値の型を明示的に宣言することです。 –

関連する問題