MSVC может найти соответствующий конструктор, но gcc и clang не смогли

#c #gcc #visual-c #clang

Вопрос:

Поэтому недавно я заинтересовался созданием кортежа с тегами, который является кортежем, но вы можете использовать функцию get с тегами вместо индексов. Код довольно длинный, так что со мной все просто.

 // tagged_tuple.hpp // simple class to hold two types // works with incomplete types, important for our use case template lt;class First, class Secondgt; struct type_pair {  using first = First;  using second = Second; };  namespace detail {  // gets info about a classes name tag (key -gt; value type mapping) from the class  template lt;class Tgt;  struct name_tag_traits {  // aliases for our specific use case  using tag_type = typename T::first;  using value_type = typename T::second;  };   // helper alias, turns a list of TypePairs supplied to tagged_tuple to a list of  // key/tag/name types  template lt;class Tgt;  using name_tag_t = typename name_tag_traitslt;Tgt;::tag_type;   // same as above but returns a list of value types  template lt;class Tgt;  using name_tag_value_t = typename name_tag_traitslt;Tgt;::value_type;   template lt;class Tgt; struct Base {};  template lt;class... Tsgt;  struct TypeSet : Baselt;Tsgt;... {  template lt;class Tgt;  constexpr auto operator   (Baselt;Tgt;) {  if constexpr (std::is_base_of_vlt;Baselt;Tgt;, TypeSetgt;) {  return TypeSet{};  }  else {  return TypeSetlt;Ts..., Tgt;{};  }  }  constexpr auto size() const -gt; std::size_t { return sizeof...(Ts); }  };   // checks if tags are unique  template lt;class... Typesgt;  constexpr auto are_tags_unique() -gt; bool {  constexpr auto typeset = (TypeSetlt;gt;{}   ...   Baselt;name_tag_tlt;Typesgt;gt;{});  return typeset.size() == sizeof...(Types);  }   template lt;class Needlegt;  constexpr auto index_of_impl(size_t index, size_t end) -gt; std::size_t {  return end;  };   template lt;class Needle, class T, class... Haystackgt;  constexpr auto index_of_impl(size_t index, size_t end) -gt; std::size_t {  return std::is_samelt;Needle, Tgt;::value  ? index  : index_of_impllt;Needle, Haystack...gt;(index   1, end);  };   // find the index of T in a type list, returns sizeof...(Haystack)   1 on failure (think std::end())  template lt;class Needle, class... Haystackgt;  static constexpr auto index_of() -gt; std::size_t {  return index_of_impllt;Needle, Haystack...gt;(0, sizeof...(Haystack)   1);  };  }; // namespace detail  // and here's our little wrapper class that enables tagged tuples template lt;class... TypePairsgt; class tagged_tuple : public std::tuplelt;detail::name_tag_value_tlt;TypePairsgt;...gt; { public:  // throws an error if tags are not unique  static_assert(detail::are_tags_uniquelt;TypePairs...gt;(), "Duplicated tags!");  // not really needed for now but if we switch to private inheritance it'll come in handy  using tag_type = std::tuplelt;detail::name_tag_tlt;TypePairsgt;...gt;;  using value_type = std::tuplelt;detail::name_tag_value_tlt;TypePairsgt;...gt;;  using value_type::value_type;  using value_type::swap;  using value_type::operator =; };  // our special get functions template lt;class Name, class... TypePairsgt; auto get(tagged_tuplelt;TypePairs...gt;amp; tuple) -gt; typename std::tuple_elementlt;  detail::index_oflt;Name, detail::name_tag_tlt;TypePairsgt;...gt;(),  typename tagged_tuplelt;TypePairs...gt;::value_typegt;::typeamp; {  return std::getlt;detail::index_oflt;Name, detail::name_tag_tlt;TypePairsgt;...gt;()gt;(  tuple); };  template lt;class Name, class... TypePairsgt; auto get(const tagged_tuplelt;TypePairs...gt;amp; tuple) -gt; const typename std::tuple_elementlt;  detail::index_oflt;Name, detail::name_tag_tlt;TypePairsgt;...gt;(),  typename tagged_tuplelt;TypePairs...gt;::value_typegt;::typeamp; {  return std::getlt;detail::index_oflt;Name, detail::name_tag_tlt;TypePairsgt;...gt;()gt;(  tuple); };  template lt;class Name, class... TypePairsgt; auto get(tagged_tuplelt;TypePairs...gt;amp;amp; tuple) -gt; typename std::tuple_elementlt;  detail::index_oflt;Name, detail::name_tag_tlt;TypePairsgt;...gt;(),  typename tagged_tuplelt;TypePairs...gt;::value_typegt;::typeamp;amp; {  return std::getlt;detail::index_oflt;Name, detail::name_tag_tlt;TypePairsgt;...gt;()gt;(  std::move(tuple)); };  

И синтаксис был бы:

 // main.cpp using foo = tagged_tuplelt;type_pairlt;class bar, intgt;, type_pairlt;class baz, std::stringgt;gt;; foo a{ 1, "foo" }; std::cout lt;lt; getlt;bargt;(a) lt;lt; " " lt;lt; getlt;bazgt;(a);  

Выход:

 1 foo  

Все шло нормально, пока я не протестировал этот фрагмент кода:

 std::tuplelt;int, std::stringgt; a{ 1, "foo" }; foo b{ a };  

что, по моей теории, должно сработать, поскольку tagged_tuple является производным от std::tuple и для этого случая имеет конструктор. Затем я протестировал в Visual Studio 2019, и это полностью сработало. Но когда я пытаюсь использовать gcc/clang, я получаю эту ошибку:

 error: no matching constructor for initialization of 'foo' (aka 'tagged_tuplelt;type_pairlt;class bar, intgt;, type_pairlt;class baz, std::stringgt;gt;')  foo b{ a };  

Что странно, так как я уже включил все конструкторы базового класса using value_type::value_type (насколько мне известно). Затем я добавил следующий конструктор:

 template lt;class... Typesgt; constexpr tagged_tuple(std::tuplelt;Types...gt; amp;tuple) : value_type(tuple) {}  

И на этот раз это сработало. Я не могу понять, почему это не сработало бы без этого фрагмента кода.

Есть ли ошибка в gcc/clang или я что-то упускаю?

Комментарии:

1. Он компилируется , если я изменю его на using typename value_type::tuple; , но я не думал, что вам это нужно typename . Может быть, вам подойдет псевдоним.

2. Обновление: Похоже, что Visual Studio 2022 также не работает. Может быть, это просто вопрос ПРОТИВ 2019 года?

3. @chris я перешел на это, и на этот раз лязг сработал, но gcc этого не сделал. Что, черт возьми, здесь происходит

4. Я готов поспорить, что вы обнаружили по крайней мере одну ошибку компилятора, как это может произойти с тяжелыми шаблонами, но это также может быть что-то вроде IFNDR, где все компиляторы будут правильными.

5. Вы не можете наследовать конструкторы копирования, поэтому преобразование из другого типа может зависеть от сведений об одном из конструкторов tuple .