2017-05-13 3 views
13

Der folgende Code kompiliert gut:C++ 17-Variante <any> innerhalb der Klasse

int main() 
{ 
    variant<any> var; 
    var = 5; 
    cout << any_cast<int>(get<any>(var)) << endl; 
    return 0; 
} 

Aber wenn ich versuche, variant<any> als Klasse Mitglied

struct MyClass{ 
    variant<any> var; 
}; 

int main() 
{ 
    MyClass s; 
    return 0; 
} 

Es macht zu setzen nicht kompilieren . Mache ich etwas falsch oder ist es ein Fehler?

Ich bin mit gcc 7.1.0

In file included from /home/zak/Projects/Anytest/main.cpp:3:0: 
/usr/local/gcc-7.1/include/c++/7.1.0/variant: In instantiation of ‘struct std::__detail::__variant::__accepted_index<const std::variant<std::any>&, std::variant<std::any>, void>’: 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:911:26: required from ‘constexpr const size_t std::variant<std::any>::__accepted_index<const std::variant<std::any>&>’ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:940:6: required by substitution of ‘template<class _Tp, class> constexpr std::variant<std::any>::variant(_Tp&&) [with _Tp = const std::variant<std::any>&; <template-parameter-1-2> = <missing>]’ 
/home/zak/Projects/Anytest/main.cpp:14:13: required from here 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:559:49: error: no matching function for call to ‘std::__detail::__variant::__overload_set<std::any>::_S_fun(const std::variant<std::any>&)’ 
     decltype(__overload_set<_Types...>::_S_fun(std::declval<_Tp>()), 
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: candidate: static std::integral_constant<long unsigned int, sizeof... (_Rest)> std::__detail::__variant::__overload_set<_First, _Rest ...>::_S_fun(_First) [with _First = std::any; _Rest = {}] 
     static integral_constant<size_t, sizeof...(_Rest)> _S_fun(_First); 
                  ^~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: no known conversion for argument 1 from ‘const std::variant<std::any>’ to ‘std::any’ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate: static void std::__detail::__variant::__overload_set<_Types>::_S_fun() [with _Types = {}] 
    { static void _S_fun(); }; 
        ^~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate expects 0 arguments, 1 provided 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:559:49: error: no matching function for call to ‘std::__detail::__variant::__overload_set<std::any>::_S_fun(const std::variant<std::any>&)’ 
     decltype(__overload_set<_Types...>::_S_fun(std::declval<_Tp>()), 
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: candidate: static std::integral_constant<long unsigned int, sizeof... (_Rest)> std::__detail::__variant::__overload_set<_First, _Rest ...>::_S_fun(_First) [with _First = std::any; _Rest = {}] 
     static integral_constant<size_t, sizeof...(_Rest)> _S_fun(_First); 
                  ^~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: no known conversion for argument 1 from ‘const std::variant<std::any>’ to ‘std::any’ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate: static void std::__detail::__variant::__overload_set<_Types>::_S_fun() [with _Types = {}] 
    { static void _S_fun(); }; 
        ^~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate expects 0 arguments, 1 provided 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:559:49: error: no matching function for call to ‘std::__detail::__variant::__overload_set<std::any>::_S_fun(const std::variant<std::any>&)’ 
     decltype(__overload_set<_Types...>::_S_fun(std::declval<_Tp>()), 
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: candidate: static std::integral_constant<long unsigned int, sizeof... (_Rest)> std::__detail::__variant::__overload_set<_First, _Rest ...>::_S_fun(_First) [with _First = std::any; _Rest = {}] 
     static integral_constant<size_t, sizeof...(_Rest)> _S_fun(_First); 
                  ^~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: no known conversion for argument 1 from ‘const std::variant<std::any>’ to ‘std::any’ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate: static void std::__detail::__variant::__overload_set<_Types>::_S_fun() [with _Types = {}] 
    { static void _S_fun(); }; 
        ^~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate expects 0 arguments, 1 provided 
/usr/local/gcc-7.1/include/c++/7.1.0/variant: In instantiation of ‘constexpr const size_t std::__detail::__variant::__accepted_index<const std::variant<std::any>&, std::variant<std::any>, void>::value’: 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:911:26: required from ‘constexpr const size_t std::variant<std::any>::__accepted_index<const std::variant<std::any>&>’ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:940:6: required by substitution of ‘template<class _Tp, class> constexpr std::variant<std::any>::variant(_Tp&&) [with _Tp = const std::variant<std::any>&; <template-parameter-1-2> = <missing>]’ 
/home/zak/Projects/Anytest/main.cpp:14:13: required from here 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:564:12: error: no matching function for call to ‘std::__detail::__variant::__overload_set<std::any>::_S_fun(const std::variant<std::any>&)’ 
    - decltype(__overload_set<_Types...>:: 
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     _S_fun(std::declval<_Tp>()))::value; 
     ~~~~~~^~~~~~~~~~~~~~~~~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: candidate: static std::integral_constant<long unsigned int, sizeof... (_Rest)> std::__detail::__variant::__overload_set<_First, _Rest ...>::_S_fun(_First) [with _First = std::any; _Rest = {}] 
     static integral_constant<size_t, sizeof...(_Rest)> _S_fun(_First); 
                  ^~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:541:58: note: no known conversion for argument 1 from ‘const std::variant<std::any>’ to ‘std::any’ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate: static void std::__detail::__variant::__overload_set<_Types>::_S_fun() [with _Types = {}] 
    { static void _S_fun(); }; 
        ^~~~~~ 
/usr/local/gcc-7.1/include/c++/7.1.0/variant:535:19: note: candidate expects 0 arguments, 1 provided 
+3

Interessanterweise macht das Ersetzen der Standardinitialisierung durch die Wertinitialisierung den Code auf GCC kompiliert. http://coliru.stacked-crooked.com/a/d45087050b803e45 – StoryTeller

+3

Durch das Löschen des Kopierkonstruktors wird auch der Code kompiliert: http://coliru.stacked-crooked.com/a/a7481101122a17a0 –

+1

Kompilieren des zweiten Beispiels mit Visual Studio 2017 und das Flag '/ std: C++ latest' funktioniert einwandfrei. Entweder GCC scheiterte oder MSVC hatte Glück. Ich werde weiter testen ... – InternetAussie

Antwort

10

Das Problem ist mit MyClass ist implizit definiert Copykonstruktor, wenn er versucht, std::variant<std::any> das Mitglied des Typs zu kopieren zu konstruieren.

Überlastung Auflösung auszuführen, der Compiler muss zuerst versuchen, all std::variant ‚s Konstruktor Vorlagen zu instanziiert, mit dem Funktionsargument ein const std::variant<std::any>& zu sein. Der Konstruktor unseres Interesses ist diese:

template <class T> constexpr variant(T&& t) noexcept(/*...*/); 

Es ist nur in der Überladungsauflösung beteiligt sich, wenn unter anderem wird der Ausdruck FUN(​std​::​forward<T>(t)) gut gebildet, wo FUN eine Reihe von überladenen Funktionen ist gemäß produziert [variant.ctor]/12. 2

In diesem Fall gibt es nur einen alternativen Typ (std::any), so gibt es nur eine imaginäre Funktion FUN, dessen Signatur ist FUN(std::any). Jetzt muss der Compiler entscheiden, ob FUN mit einem const std::variant<std::any>& aufgerufen werden kann. In diesem Prozess muss der Compiler wissen, ob std::any mit const std::variant<std::any>& konstruiert werden kann.

Dies wird die Instantiierung std::any ‚s Konstruktors Vorlage template<class T> any(T&& value);, auslösen, die in der Überladungsauflösung nimmt nur dann, wenn std::is_­copy_­constructible_­v<VT> ist true (VTstd::decay_t<T> zu sein, und Tconst std::variant<std::any>& wird).

Um nun zu sehen, ob VT (dh std::variant<std::any>) kopieren konstruierbar ist, muss der Compiler versuchen, alle std::variant ‚Konstruktor Vorlagen zu instanziiert ... und das ist, wo wir angefangen haben, und wir stecken in einer Schleife .

Dies kann erklären, warum wir template<class _Tp, class> constexpr std::variant<std::any>::variant(_Tp&&) und __overload_set<std::any>::_S_fun sehen (die FUN oben erwähnt auf die Funktion entspricht) in der Fehlermeldung, und warum wir die gleichen Fehler erscheinen mehrmals zu sehen.

Es bleibt eine Frage, wie GCC aus der obigen Schleife bricht, und warum das Programm optimieren kann GCC von der Meldung des Fehlers zu stoppen. Vielleicht sind dies Anzeichen für einen Fehler.


1. Streng genommen sollte es „ein L-Wert vom Typ const std::variant<std::any>“ statt „ein const std::variant<std::any>&“ sein.

2. Der Standard verlangt auch, dass dieser Konstruktor nur in der Überladungsauflösung teilnehmen soll, wenn is_­same_­v<decay_­t<T>, variant>false ist. GCC (libstdC++) wählt dies später aus. Ich weiß nicht, ob das stimmt.

Verwandte Themen