2017-08-28 5 views
3

Hier ist mein Code:Variante: keine passende Funktion für Aufruf von ‚get‘

#include <iostream> 
#include <variant> 
#include <vector> 

class A { 
public: 
    virtual void Foo() = 0;  
}; 

class B : public A { 
public: 
    void Foo() override { 
     std::cout << "B::Foo()" << std::endl; 
    } 
}; 

class C :public A { 
public: 
    void Foo() override { 
     std::cout << "C::Foo()" << std::endl; 
    } 
}; 

template<typename... Args> 
class D { 
public: 
    template<typename T> 
    void Foo() { 
     m_variant = T{}; 
    } 

    void Bar() { 
     std::get<m_variant.index()>(m_variant).Foo(); 
    } 

private: 
    std::variant<std::monostate, Args...> m_variant; 
}; 

int main() { 
    D<B, C> d; 
    d.Foo<B>(); 
    d.Bar(); 

    d.Foo<C>(); 
    d.Bar(); 
} 

(C, F wandbox.org)

Ich erhalte den Fehler no matching function for call to 'get' aber ich herausfinden, nicht warum. std::variant::index() ist conexpr, so ist es nicht das Problem (ich habe getestet, indem ich direkt den Wert 1, aber immer noch den gleichen Fehler).
Ich habe eine std::monostate eine leere Variante zu verhindern

+5

'm_variant.index()' ist ein Laufzeitwert, Verwendung Besucher statt ('std :: Besuch ([] (auto & e) {e.Foo();}, m_variant); '). – Jarod42

+3

Obwohl es stimmt, dass die Funktion ['index'] (http://en.cppreference.com/w/cpp/utility/variant/index) als 'constexpr' gekennzeichnet ist, ist die Variable 'm_variant' * nicht * und kann daher nicht zur Kompilierzeit verwendet werden. –

+3

Das Ergebnis von 'std :: variant :: index()' ist nur dann ein konstanter Ausdruck, wenn das Variantenobjekt, für das es aufgerufen wird, ein konstanter Ausdruck ist. Deines ist nicht. – StoryTeller

Antwort

4

m_variant.index() ist ein Laufzeitwert (wie m_variant ist kein konstanter Ausdruck).

Der Weg ist zu versenden Besucher zu verwenden, wie:

std::visit([](auto& v) { v.Foo(); }, m_variant); 

Demo

+0

Könnten Sie bitte kurz erklären, wie "überladen" funktioniert? Ich habe [std :: visit] (http://en.cppreference.com/w/cpp/utility/variant/visit) Dokumente gesehen, aber es wird dort nicht erklärt. – AMA

+1

Es erlaubt mehrere Funktoren mit 'operator()' zu gruppieren. Das erlaubt, an der Call-Site mit Lambda zu bauen, anstatt einen dedizierten Funktor mit der ganzen Überladung für 'operator()' zu schreiben. – Jarod42

+1

@AMA - Siehe [hier] (https://stackoverflow.com/questions/45020573/using-stdvisit-with-variadic-template-struct/45020724#45020724) für eine Erklärung. – StoryTeller

1

Etwas markiert constexpr sagt Ihnen (wenn keine Argumente in typename... Args sind), dass in bestimmten Situationen kann es bei der Kompilierung aufgerufen werden. Es tut nicht Garantie es kann immer zur Kompilierzeit aufgerufen werden.

I der Fall variant, index kann bei der Kompilierung aufgerufen werden, wenn die Variante selbst ein constexpr Wert ist. Ansonsten ist es eine Laufzeitmethode.

Sie können entweder Dokumentation darüber lesen, wann zur Kompilierungszeit etwas aufgerufen werden kann, oder einen Grund dafür angeben; Wenn in diesem Fall der Variantentyp zur Laufzeit variieren könnte, wie kann index eine Kompilierzeitkonstante sein? Denken Sie daran, dass nur der Ttpe- und Constexprin-Wert von Werten, plus wenn er sich in einem Kompilierzeitkontext befindet, verwendet werden kann, um zu begründen, "kann dies zur Kompilierzeit aufgerufen werden".

Verwandte Themen