2016-11-21 91 views
12

我有下面的示例代碼,減少到必要的,與GCC 6.1,GCC 7.0頭和Visual Studio 2015/2017RC編譯,但不與任何鐺版本。爲什麼鐺拒絕可變參數模板友元函數

#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 ...)的私有成員;

我不明白爲什麼鐺不認朋友聲明。這是一個叮噹的bug還是它是所有其他編譯器的問題?

當我做富非模板類,鐺不抱怨。 解決方法的任何想法?

很多感謝

+3

不[這](http://stackoverflow.com/questions/32889492/friend-function-template-with-automatic-return- type-deduction-can-access-a-pr)回答你的問題? –

+1

作爲一種變通方法,你可以使用'朋友自動測試:: bar_(A &&,B &&,C && ... C) - > decltype(STD :: make_tuple(c._p ...));'爲朋友(以及作爲'bar_')函數簽名。 [現場演示](http://melpon.org/wandbox/permlink/CEBDjgZGGLbAtWY1) –

+0

我搜索了可變參數和朋友的組合。但我沒有意識到汽車是問題。是的,是問題和顯式指定返回類型解決了問題。由於實際的返回類型更復雜,我沒有嘗試過。非常感謝! –

回答

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_()應該是foofriend功能)。

一種解決方法可能是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; } 
}; 

添加getter getP(),並用它在bar_()

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

感謝您的回覆。但_p只是我不想公開的一個簡單例子。正如我上面所述,解決方法是顯式聲明返回類型。 –

相關問題