2016-11-21 21 views
12

Tôi có mã mẫu sau đây, được giảm xuống mức cần thiết, biên dịch với gcc 6.1, gcc 7.0 head và Visual Studio 2015/2017RC, nhưng không có bất kỳ phiên bản nào.Tại sao clang từ chối chức năng của bạn bè mẫu variadic

#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; 
} 

kêu vang nói với tôi: prog.cc:12:34: lỗi: '_P' là một thành viên tư nhân 'ngoài :: foo' trở std :: make_tuple (c._p ...) ;

Tôi không hiểu tại sao clang không nhận ra tuyên bố kết bạn. Đây có phải là một lỗi của clang hay nó là một vấn đề của tất cả các trình biên dịch khác?

Khi tôi tạo foo một lớp không phải mẫu, tiếng kêu không kêu la. Bất kỳ ý tưởng nào cho giải pháp thay thế?

Nhiều cảm ơn trước

+3

Liệu không [này] (http://stackoverflow.com/questions/32889492/friend-function-template-with-automatic-return- type-deduction-cannot-access-a-pr) trả lời câu hỏi của bạn? –

+1

Để giải quyết sự cố, bạn có thể sử dụng 'kiểm tra tự động của người bạn :: bar_ (A &&, B &&, C && ... c) -> decltype (std :: make_tuple (c._p ...)); 'làm bạn (cũng như dưới dạng chữ ký 'bar_'). [live demo] (http://melpon.org/wandbox/permlink/CEBDjgZGGLbAtWY1) –

+0

Tôi đã tìm kiếm sự kết hợp của variadic và bạn bè. Nhưng tôi đã không nhận ra sự tự động là vấn đề. Có, là vấn đề và rõ ràng xác định kiểu trả về đã giải quyết được vấn đề. Vì kiểu trả về thực tế phức tạp hơn nhiều nên tôi không thử nó. Cảm ơn nhiều! –

Trả lời

1

Là "tại sao?" câu hỏi đã được thảo luận sâu sắc trong this thread Tôi sẽ chỉ tập trung vào một giải pháp có thể. Bạn có thể cố gắng bọc chức năng của bạn thành một cấu trúc giả chỉ để đảm bảo tất cả các tình trạng quá tải có thể xảy ra trong danh sách bạn bè của bạn là foo. Các đề xuất cách giải quyết có thể nhìn như sau:

#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

Dường như với tôi một kêu vang ++ lỗi (đó là sự thật mà _pprivate, nhưng bar_() phải là một chức năng friend cho foo lớp).

Một cách giải quyết có thể là thêm một getter getP() trong 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; } 
}; 

và sử dụng nó trong bar_()

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

Cảm ơn bạn đã phản hồi. Nhưng _p chỉ là một ví dụ đơn giản về một cái gì đó mà tôi không muốn công khai. Như tôi đã nói ở trên workaround là khai báo rõ ràng kiểu trả về. –

Các vấn đề liên quan