2016-11-21 4 views
12

Ich habe den folgenden Beispielcode, reduziert auf das Wesentliche, das kompiliert mit Gcc 6.1, GCC 7.0 Kopf und Visual Studio 2015/2017RC, aber nicht mit irgendeiner Clang-Version.Warum Clang Variadic Vorlage Freund Funktion

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

Klirren sagt mir: prog.cc:12:34: Fehler: '_p' ist ein privates Mitglied von 'Außen :: foo' return std :: make_tuple (c._p ...) ;

Ich verstehe nicht, warum Clang die Freundschaftsdeklaration nicht erkennt. Ist das ein Bug des Klangs oder ist es ein Problem aller anderen Compiler?

Wenn ich foo eine Nicht-Vorlage-Klasse mache, klagt clang nicht. Irgendwelche Ideen für eine Problemumgehung?

Vielen Dank im Voraus

+3

Does not [diese] (http://stackoverflow.com/questions/32889492/friend-function-template-with-automatic-return- type-deduction-can not-access-a-pr) Beantworten Sie Ihre Frage? –

+1

Als Workaround könntest du 'friendautotest :: bar_ (A &&, B &&, C && ... c) -> decltype (std :: make_tuple (c._p ...));' als Freund benutzen als 'bar_') Funktionssignatur. [Live-Demo] (http://melpon.org/wandbox/permlink/CEBDjgZGGLbAtWY1) –

+0

Ich suchte nach der Kombination von variadic und Freund. Aber ich wusste nicht, dass das Auto das Problem war. Ja, ist das Problem und explizite Angabe des Rückgabetyps löste das Problem. Da der tatsächliche Rückgabetyp viel komplizierter ist, habe ich es nicht versucht. Danke vielmals! –

Antwort

1

Wie das "Warum?" Frage wurde ausführlich in this thread diskutiert Ich werde mich nur auf eine mögliche Problemumgehung konzentrieren. Sie könnten versuchen, Ihre Funktion in eine Dummy-Struktur zu verpacken, nur um sicherzustellen, dass alle möglichen Überladungen davon auch in einer Freundesliste Ihrer foo enthalten sind. Die Abhilfe Satz könnte wie folgt aussehen:

#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

Es scheint mir ein Klirren ++ Fehler (es wahr ist, dass _p ist private, aber bar_() sollte eine friend Funktion für foo Klasse).

konnte Eine Abhilfe einen Getter getP() in 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; } 
}; 

und es verwenden, fügen Sie werden in bar_()

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

Danke für die Antwort. Aber _p war nur ein einfaches Beispiel für etwas, das ich nicht veröffentlichen möchte. Wie bereits erwähnt, besteht die Problemumgehung darin, den Rückgabetyp explizit anzugeben. –

Verwandte Themen