Wie schreibe ich ein Typmerkmal `is_container` oder `is_vector`?

Lesezeit: 7 Minuten

Ist es möglich, ein Typmerkmal zu schreiben, dessen Wert für alle gängigen STL-Strukturen wahr ist (z. B. vector, set, map…)?

Zu Beginn möchte ich ein Typmerkmal schreiben, das für a gilt vector und falsch sonst. Ich habe es versucht, aber es lässt sich nicht kompilieren:

template<class T, typename Enable = void>
struct is_vector {
  static bool const value = false;
};

template<class T, class U>
struct is_vector<T, typename boost::enable_if<boost::is_same<T, std::vector<U> > >::type> {
  static bool const value = true;
};

Die Fehlermeldung ist template parameters not used in partial specialization: U.

Wie schreibe ich ein Typmerkmal is container oder is vector
Nimmermehr

Schauen Sie, eine weitere SFINAE-basierte Lösung zum Erkennen von STL-ähnlichen Containern:

template<typename T, typename _ = void>
struct is_container : std::false_type {};

template<typename... Ts>
struct is_container_helper {};

template<typename T>
struct is_container<
        T,
        std::conditional_t<
            false,
            is_container_helper<
                typename T::value_type,
                typename T::size_type,
                typename T::allocator_type,
                typename T::iterator,
                typename T::const_iterator,
                decltype(std::declval<T>().size()),
                decltype(std::declval<T>().begin()),
                decltype(std::declval<T>().end()),
                decltype(std::declval<T>().cbegin()),
                decltype(std::declval<T>().cend())
                >,
            void
            >
        > : public std::true_type {};

Natürlich können Sie die zu überprüfenden Methoden und Typen ändern.

Wenn Sie nur STL-Container erkennen möchten (dh std::vector, std::listusw.) sollten Sie so etwas tun.

AKTUALISIEREN. Wie @Deduplicator feststellte, erfüllt der Container möglicherweise nicht die AllocatorAwareContainer-Anforderungen (z. B.: std::array<T, N>). Deshalb check on T::allocator_type ist nicht notwendig. Aber Sie können alle/alle ankreuzen Container Anforderungen in ähnlicher Weise.

  • is_cointainer_helper kann heutzutage durch std::void_t ersetzt werden

    – Arvid

    20. Dezember 17 um 20:43 Uhr

  • Für beide is_container Strukturen, void wird als zweites verwendet Parameter. Nach Tests scheint es, dass es unabhängig vom Typ funktioniert, wenn dies derselbe Typ ist: template<typename T, typename _ = int> und is_container_helper<...>, int>. Warum so? Warum funktioniert es nicht, wenn wir verwenden void und intoder int und void?

    – Maxime Recuerda

    20. November 18 um 15:57 Uhr

  • Weil Sie verwenden is_container< Type > welches ist is_container< Type, void > die nicht spezialisiert ist und die Standardimplementierung verwendet wird: std::false_type

    – Nie wieder

    23. November 18 um 9:02 Uhr

  • EIN Container ist vielleicht kein AllocatorAwareContainer.

    – Deduplizierer

    31. Mai ’19 um 14:35 Uhr

  • Bei Verwendung von std::void_t Sie können entsorgen std::conditional_t?

    – Marek R

    6. Dezember 19 um 15:32 Uhr


1643911807 556 Wie schreibe ich ein Typmerkmal is container oder is vector
Frank

Eigentlich habe ich nach einigem Ausprobieren festgestellt, dass es ganz einfach ist:

template<class T>
struct is_vector<std::vector<T> > {
  static bool const value = true;
};

Ich würde immer noch gerne wissen, wie man eine allgemeinere schreibt is_container. Muss ich alle Typen von Hand auflisten?

  • +1 … duh! (Vielleicht möchten Sie die hinzufügen allocator_type Auch dort ist die Eigenschaft, wie sie ist, wirklich is_vector_with_default_allocator

    – David Rodríguez – Dribeas

    20. August 2012 um 18:34 Uhr


  • @AndrewDurward: Danke, behoben.

    – Frank

    20. August 2012 um 22:10 Uhr

  • 6 Jahre danach 🙂 Würden Sie gerne einen Link zu einer Online-Ide posten, wo Sie ein minimales Anwendungsbeispiel platziert haben? Danke

    Benutzer5560811

    22. Februar 18 um 14:03 Uhr

  • @NoSenseEtAl das ist falscher Code. auto isv = is_vector::value ; ist explizite Spezialisierung der Nicht-Template-Struktur ‘is_vector’ … check

    Benutzer5560811

    26. Juni 18 um 15:35 Uhr

  • Sie brauchen zuerst eine falsche allgemeine Vorlage wandbox.org/permlink/76dOGKSuvEiBdAdw

    – NoSenseetAl

    26. Juni 18 um 15:57 Uhr

Sie würden sagen, es sollte einfacher sein als das …

template <typename T, typename _ = void>
struct is_vector { 
    static const bool value = false;
};
template <typename T>
struct is_vector< T,
                  typename enable_if<
                      is_same<T,
                              std::vector< typename T::value_type,
                                           typename T::allocator_type >
                             >::value
                  >::type
                >
{
    static const bool value = true;
};

… Aber ich bin mir nicht sicher, ob das so ist einfacher oder nicht.

In C ++ 11 können Sie Typaliase verwenden (glaube ich, ungetestet):

template <typename T>
using is_vector = is_same<T, std::vector< typename T::value_type,
                                          typename T::allocator_type > >;

Das Problem mit Ihrem Ansatz ist, dass der Typ U ist in dem Kontext, in dem es verwendet wird, nicht ableitbar.

  • Und für is_container? einfach testen, ob es eine hat allocator_type?

    – TemplateRex

    20. August 2012 um 18:31 Uhr

  • @rhalbersma: Das Problem ist, was Sie definieren is_container ist… Ist meine Hand gerollt single_list ein Container? ist std::string ein Container? Macht die Tatsache, dass es einen Allocator hat, ein Objekt zu einem Container?

    – David Rodríguez – Dribeas

    20. August 2012 um 18:33 Uhr

  • Pro is_containerviele Leute suchen nur begin und end Funktionen und Verwendung is_iterabledas ist (meistens) das, was Sie sowieso wirklich wissen mussten.

    – Muhende Ente

    20. August 2012 um 19:08 Uhr

  • @MooingDuck: Wo finde ich is_iterable?

    – Frank

    6. Dezember 2012 um 19:40 Uhr

  • Es ist erwähnenswert, dass die ungetestete „using“-Syntax in diesem Fall nur schlecht funktioniert. Es wird versucht, eine Instanziierung des abhängigen Typs “T::value_type” zu erzwingen, was mit einem Kompilierfehler fehlschlägt, wenn T so etwas wie int ist.

    – ltd

    24. Februar 15 um 19:39 Uhr

Während die anderen Antworten hier, die versuchen zu erraten, ob eine Klasse ein Container ist oder nicht, für Sie funktionieren könnten, möchte ich Ihnen die Alternative vorstellen, den Typ zu benennen, für den Sie true zurückgeben möchten. Sie können dies verwenden, um beliebige zu erstellen is_(something) Eigenschaften Typen.

template<class T> struct is_container : public std::false_type {};

template<class T, class Alloc> 
struct is_container<std::vector<T, Alloc>> : public std::true_type {};

template<class K, class T, class Comp, class Alloc> 
struct is_container<std::map<K, T, Comp, Alloc>> : public std::true_type {};

Und so weiter.

Sie müssen einbeziehen <type_traits> und welche Klassen Sie Ihren Regeln hinzufügen.

Warum nicht so etwas für is_container?

template <typename Container>
struct is_container : std::false_type { };

template <typename... Ts> struct is_container<std::list<Ts...> > : std::true_type { };
template <typename... Ts> struct is_container<std::vector<Ts...> > : std::true_type { };
// ...

Auf diese Weise können Benutzer ihre eigenen Container hinzufügen, indem sie sich teilweise spezialisieren. Verwenden Sie für is_vector et al. nur eine teilweise Spezialisierung wie oben, aber beschränken Sie sie auf nur einen Containertyp, nicht viele.

template <typename T>
struct is_container {

    template <
       typename U,
       typename I = typename U::const_iterator
    >   
    static int8_t      test(U* u); 

    template <typename U>
    static int16_t     test(...);

    enum { value  =  sizeof test <typename std::remove_cv<T>::type> (0) == 1 };
};


template<typename T, size_t N>  
struct  is_container <std::array<T,N>>    : std::true_type { };

Wie schreibe ich ein Typmerkmal is container oder is vector
Arvid

Die Art und Weise, wie ich feststellen möchte, ob etwas ein Container ist, ist zu suchen data() und size() Mitgliedsfunktionen. So was:

template <typename T, typename = void>
struct is_container : std::false_type {};

template <typename T>
struct is_container<T
   , std::void_t<decltype(std::declval<T>().data())
      , decltype(std::declval<T>().size())>> : std::true_type {};

  • netter Stunt. Aber das wird “machen” std::string (zum Beispiel) auch in einen Behälter . Mit dem oben genannten: is_container<std::string>::value ist true

    Benutzer5560811

    27. Juni 18 um 08:43 Uhr


  • so wie es sollte! stackoverflow.com/questions/17259595/…

    – Arvid

    28. Juni 18 um 9:45 Uhr

  • Ich habe bis jetzt geglaubt std::string ist kein Standardcontainer? Obwohl ich zustimme Dieser Text.

    Benutzer5560811

    28. Juni 18 um 9:55 Uhr


.

758470cookie-checkWie schreibe ich ein Typmerkmal `is_container` oder `is_vector`?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy