Jak sprawdzić, czy dany typ znajduje się wśród argumentów szablonu wariadycznego?

1
#include <type_traits>

template<typename...Types> struct type_collection
{ 
  public:
    template<typename Type> struct collection_element
    {
      private:
        template<typename DoesHave, typename T, typename...Rest>
        static constexpr bool hasType()
        {
          return std::is_same<DoesHave, T>::value?true:
          sizeof...(Rest)==0?false:
          hasType<DoesHave, Rest...>();
       }
       
      public:
        static_assert(hasType<Type, Types...>(), "No such type in the collection");
    };
};

struct TypeA {};
struct TypeB {};
struct TypeC {};

int main()
{
  using check1 = type_collection<TypeA, TypeB>::collection_element<TypeA>;
  using check2 = type_collection<TypeA, TypeB>::collection_element<TypeC>;
  
  check1 c1;
  check2 c2;
}

Kod jest pewnie zdrowo schrzaniony.

Moja intecja jest taka: type_collection<TypeA, TypeB>::collection_element<TypeA> powinno się kompilować, bo TypeA jest w kolekcji, zaś type_collection<TypeA, TypeB>::collection_element<TypeC> już nie (bo TypeC nie jest wśród TypeA, TypeB).

To sprawdzanie odbywa się przez funkcję hasType<Type, Types...>(). Funkcja ma rekurencyjnie sprawdzać, czy argument Type znajduje się wśród argumentów Types..., za każdym wywołaniem porównując Type z pierwszym spośród Types... i wywołując się rekurencyjnie z Types... okrojonymi o pierwszy argument.

Nie kompiluje się. I niestety, nie wiem, jak to poprawić. Mógłby ktoś coś poradzić? Dzięki!

wtf.cc:14:11: error: use of undeclared identifier 'hasType'
          hasType<DoesHave, Rest...>();
          ^
wtf.cc:14:11: note: in instantiation of function template specialization
      'type_collection<TypeA, TypeB>::collection_element<TypeA>::hasType<TypeA,
      TypeB>' requested here
          hasType<DoesHave, Rest...>();
          ^
wtf.cc:18:23: note: in instantiation of function template specialization
      'type_collection<TypeA, TypeB>::collection_element<TypeA>::hasType<TypeA,
      TypeA, TypeB>' requested here
        static_assert(hasType<Type, Types...>(), "No such type in the co...
                      ^
wtf.cc:31:10: note: in instantiation of template class 'type_collection<TypeA,
      TypeB>::collection_element<TypeA>' requested here
  check1 c1;
         ^
wtf.cc:10:31: note: must qualify identifier to find this declaration in
      dependent base class
        static constexpr bool hasType()
                              ^
wtf.cc:14:11: error: no matching function for call to 'hasType'
          hasType<DoesHave, Rest...>();
          ^~~~~~~~~~~~~~~~~~~~~~~~~~
wtf.cc:10:31: note: candidate template ignored: couldn't infer template argument
      'T'
        static constexpr bool hasType()
                              ^
wtf.cc:14:11: error: no matching function for call to 'hasType'
          hasType<DoesHave, Rest...>();
          ^~~~~~~~~~~~~~~~~~~~~~~~~~
wtf.cc:10:31: note: candidate template ignored: couldn't infer template argument
      'T'
        static constexpr bool hasType()
                              ^
wtf.cc:14:11: error: use of undeclared identifier 'hasType'
          hasType<DoesHave, Rest...>();
          ^
wtf.cc:14:11: note: in instantiation of function template specialization
      'type_collection<TypeA, TypeB>::collection_element<TypeC>::hasType<TypeC,
      TypeB>' requested here
          hasType<DoesHave, Rest...>();
          ^
wtf.cc:18:23: note: in instantiation of function template specialization
      'type_collection<TypeA, TypeB>::collection_element<TypeC>::hasType<TypeC,
      TypeA, TypeB>' requested here
        static_assert(hasType<Type, Types...>(), "No such type in the co...
                      ^
wtf.cc:32:10: note: in instantiation of template class 'type_collection<TypeA,
      TypeB>::collection_element<TypeC>' requested here
  check2 c2;
         ^
wtf.cc:10:31: note: must qualify identifier to find this declaration in
      dependent base class
        static constexpr bool hasType()
                              ^
wtf.cc:14:11: error: no matching function for call to 'hasType'
          hasType<DoesHave, Rest...>();
          ^~~~~~~~~~~~~~~~~~~~~~~~~~
wtf.cc:10:31: note: candidate template ignored: couldn't infer template argument
      'T'
        static constexpr bool hasType()
                              ^
wtf.cc:14:11: error: no matching function for call to 'hasType'
          hasType<DoesHave, Rest...>();
          ^~~~~~~~~~~~~~~~~~~~~~~~~~
wtf.cc:10:31: note: candidate template ignored: couldn't infer template argument
      'T'
        static constexpr bool hasType()
                              ^
wtf.cc:18:23: error: static_assert expression is not an integral constant
      expression
        static_assert(hasType<Type, Types...>(), "No such type in the co...
                      ^~~~~~~~~~~~~~~~~~~~~~~~~
wtf.cc:32:10: note: in instantiation of template class 'type_collection<TypeA,
      TypeB>::collection_element<TypeC>' requested here
  check2 c2;
         ^
7 errors generated.
0

Jeśli miałbyś to w postaci listy to rozwiązanie jest proste ( nawet dla mnie ;) )

struct TypeListEnd { 
  using Head = TypeListEnd;
using Tail = TypeListEnd;
};

template< typename ListHead, typename ListTail = TypeListEnd >
struct TypeList {
  using Head = ListHead;
  using Tail = ListTail;
};

template< typename ToCheck, typename List >
struct Contains {
  using Head = List::Head;
  using Tail = List::Tail;
  static const bool result = std::is_same< ToCheck, Head >::value || Contains< ToCheck, Tail >::result;
};

template< typename ToCheck >
struct Contains< ToCheck, TypeListEnd > {
  static const bool result = false;
};
1
#include <type_traits>
 
template<typename Type, typename... Types> struct is_any : std::false_type {};

template<typename Type, typename TNext> struct is_any<Type, TNext> : std::is_same<Type, TNext> {};

template<typename Type, typename TNext, typename... TRest> struct is_any<Type, TNext, TRest...>
    : std::integral_constant<bool, std::is_same<Type, TNext>::value || is_any<Type, TRest...>::value> {};


template<typename... Types> struct type_collection
{ 
    template<typename DoesHave> struct collection_element
    {
        static_assert(is_any<DoesHave, Types...>::value, "No such type in the collection");
    };
};
 
struct TypeA {};
struct TypeB {};
struct TypeC {};
 
int main()
{
  using check1 = type_collection<TypeA, TypeB>::collection_element<TypeA>;
  using check2 = type_collection<TypeA, TypeB>::collection_element<TypeC>;
 
  check1 c1;
  check2 c2;
}
4
#include <type_traits>
#include <iostream>
#include <string>

namespace endrju{
template<typename T, typename... Args>
struct contains : std::true_type{};

template<typename T, typename Head, typename... Tail>
struct contains<T, Head, Tail...>
    : std::conditional<std::is_same<T, Head>::value
    , std::true_type
    , contains<T, Tail...>
>::type{};

template<typename T>
struct contains<T> : std::false_type{};
}

int main() {
    std::cout << endrju::contains<int, float, double, std::string>::value << std::endl;
    std::cout << endrju::contains<int, float, int, std::string>::value << std::endl;
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1