2016-11-21 1 views
12

다음 샘플 코드는 gcc 6.1, gcc 7.0 헤드 및 Visual Studio 2015/2017RC로 컴파일되지만 필수 버전으로 축소되었습니다.왜 clang이 가변적 인 템플릿 friend 함수를 거부합니까?

#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는 ' 반환 표준 : : make_tuple과 (c._p ...)의 개인 회원입니다 ;

clang이 친구 선언을 인식하지 못하는 이유를 알 수 없습니다. 이것은 clang의 버그입니까, 아니면 다른 모든 컴파일러의 문제입니까?

foo를 템플릿이 아닌 클래스로 만들 때 clang은 불평하지 않습니다. 해결 방법에 대한 아이디어가 있으십니까? 그것은 나에게 그 소리 ++ 버그 (이 _pprivate 것은 사실이지만, bar_()foo 클래스에 대한 friend 기능이 있어야한다) 보인다 사전

+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

많은 감사합니다.

해결 방법은 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는 내가 공개하고 싶지 않은 단순한 예일뿐입니다. 위에서 설명한 것처럼 해결 방법은 반환 형식을 명시 적으로 선언하는 것입니다. –

관련 문제