23

コンパイル時に型がstlコンテナであるかどうかを判断するテンプレートを作成したいと思います。  

私は次のコードを持っています:

struct is_cont{};
struct not_cont{};

template <typename T>
struct is_cont { typedef not_cont result_t; };

しかし、私はstd::vector<T,Alloc>, deque<T,Alloc>, set<T,Alloc,Comp>などに必要な専門分野を作成する方法がわかりません...

4

9 に答える 9

29

注:次のコードは、 @ Kerrek SB(stackoverflowでのトピック)によって作成されたpretty-printと呼ばれる優れたユーティリティから取得したものです。

免責事項:元の作者の許可を得ずにこのコードをコピーしてここに貼り付けることが許可されているかどうかはわかりません。@Kerrek、何か問題があれば教えてください。:-)


このクラステンプレートを使用できます。

  template<typename T> 
  struct is_container : std::integral_constant<bool, has_const_iterator<T>::value && has_begin_end<T>::beg_value && has_begin_end<T>::end_value> 
  { };

使用法:

 std::cout << is_container<std::vector<int>>::value << std::endl; //true
 std::cout << is_container<std::list<int>>::value << std::endl;   //true 
 std::cout << is_container<std::map<int>>::value << std::endl;    //true
 std::cout << is_container<std::set<int>>::value << std::endl;    //true
 std::cout << is_container<int>::value << std::endl;              //false

is_container次のヘルパークラステンプレートが必要であることに注意してください。

template<typename T>
struct has_const_iterator
{
private:
    typedef char                      yes;
    typedef struct { char array[2]; } no;

    template<typename C> static yes test(typename C::const_iterator*);
    template<typename C> static no  test(...);
public:
    static const bool value = sizeof(test<T>(0)) == sizeof(yes);
    typedef T type;
};

template <typename T>
struct has_begin_end
{
    template<typename C> static char (&f(typename std::enable_if<
      std::is_same<decltype(static_cast<typename C::const_iterator (C::*)() const>(&C::begin)),
      typename C::const_iterator(C::*)() const>::value, void>::type*))[1];

    template<typename C> static char (&f(...))[2];

    template<typename C> static char (&g(typename std::enable_if<
      std::is_same<decltype(static_cast<typename C::const_iterator (C::*)() const>(&C::end)),
      typename C::const_iterator(C::*)() const>::value, void>::type*))[1];

    template<typename C> static char (&g(...))[2];

    static bool const beg_value = sizeof(f<T>(0)) == 1;
    static bool const end_value = sizeof(g<T>(0)) == 1;
};
于 2012-02-23T05:09:51.477 に答える
20

最初に、プライマリテンプレートを定義します。このテンプレートには、デフォルトの場合はfalseのメンバーが含まれます。

template <typename T>
struct is_cont {
  static const bool value = false;
};

次に、代わりにtrueの値を持つコンテナタイプの部分的な特殊化を定義します。

template <typename T,typename Alloc>
struct is_cont<std::vector<T,Alloc> > {
  static const bool value = true;
};

次に、チェックしたいタイプXについては、次のように使用します。

if (is_cont<X>::value) { ... } 
于 2012-02-23T04:57:01.743 に答える
18

has-an-stl-container-like-interfaceの一般的なコンパイル時テストが 適切な解決策であるという提案を追求して、これはインターフェースによってstlのようなコンテナー Tを定義 します。

T::iterator T::begin();
T::iterator T::end();
T::const_iterator T::begin() const;
T::const_iterator T::end() const;

*T::iterator is T::value_type &
*T::const_iterator is T::value_type const &

メソッドなどの追加要件をsize()明白な方法で追加することも、コンパイル時に明白な同様の方法でプローブされる他の正規型インターフェースを追加することもできます。

#ifndef IS_STL_CONTAINER_LIKE_H
#define IS_STL_CONTAINER_LIKE_H

#include <type_traits>

template<typename T>
struct is_stl_container_like
{
    typedef typename std::remove_const<T>::type test_type;

    template<typename A>
    static constexpr bool test(
        A * pt,
        A const * cpt = nullptr,
        decltype(pt->begin()) * = nullptr,
        decltype(pt->end()) * = nullptr,
        decltype(cpt->begin()) * = nullptr,
        decltype(cpt->end()) * = nullptr,
        typename A::iterator * pi = nullptr,
        typename A::const_iterator * pci = nullptr,
        typename A::value_type * pv = nullptr) {

        typedef typename A::iterator iterator;
        typedef typename A::const_iterator const_iterator;
        typedef typename A::value_type value_type;
        return  std::is_same<decltype(pt->begin()),iterator>::value &&
                std::is_same<decltype(pt->end()),iterator>::value &&
                std::is_same<decltype(cpt->begin()),const_iterator>::value &&
                std::is_same<decltype(cpt->end()),const_iterator>::value &&
                std::is_same<decltype(**pi),value_type &>::value &&
                std::is_same<decltype(**pci),value_type const &>::value;

    }

    template<typename A>
    static constexpr bool test(...) {
        return false;
    }

    static const bool value = test<test_type>(nullptr);

};

#endif

これは、GCC 4.7.2、clang 3.2、Intel C++13.1.1でビルドされたテストプログラムです。

#include "is_stl_container_like.h"

// Testing ...

#include <iostream>
#include <vector>
#include <array>
#include <functional>

using namespace std;

template<class C>
struct polymorphic : private C
{
    typedef typename C::value_type value_type;
    typedef typename C::iterator iterator;
    typedef typename C::const_iterator const_iterator;

    virtual ~polymorphic(){}

    virtual const_iterator begin() const {
        return C::begin();
    }

    virtual iterator begin()  {
        return C::begin();
    }

    virtual const_iterator end() const {
        return C::end();
    }

    virtual iterator end()  {
        return C::end();
    }   
};

template<class C>
struct reject : private C
{
    typedef typename C::value_type value_type;
    typedef typename C::iterator iterator;
    typedef typename C::const_iterator const_iterator;


    const_iterator begin() {
        return C::begin();
    }

    iterator begin() const {
        return C::begin();
    }

    const_iterator end() {
        return C::end();
    }

    iterator end() const {
        return C::end();
    }
};

int main()
{
    cout << is_stl_container_like<vector<int> const >::value << endl; // Yes
    cout << is_stl_container_like<array<int,42>>::value << endl; // Yes
    cout << is_stl_container_like<polymorphic<vector<int>>>::value << endl; // Yes
    cout << is_stl_container_like<function<int(int)>>::value << endl; // No
    cout << is_stl_container_like<int>::value << endl; // No
    cout << is_stl_container_like<reject<vector<int>>>::value << endl; //No
}
于 2013-05-01T10:41:40.723 に答える
18

すでに提案されているソリューションの多くは、STLコンテナーを検出するために冗長です。
それらは、コンテナが何であるかを明示的に述べるのではなく、すべてのコンテナが持つ特性に焦点を合わせています。

独自のコンテナを作成してTrueTypeで評価してもらいたい場合は、他のソリューションをお勧めします。STLのようなコンテナーではなく、正当なSTLコンテナーのみを検証する場合は、正確なSTLコンテナー検出を提供するため、次の実装の使用を検討してください。

#include <deque>
#include <forward_list>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include <type_traits>

//specialize a type for all of the STL containers.
namespace is_stl_container_impl{
  template <typename T>       struct is_stl_container:std::false_type{};
  template <typename T, std::size_t N> struct is_stl_container<std::array    <T,N>>    :std::true_type{};
  template <typename... Args> struct is_stl_container<std::vector            <Args...>>:std::true_type{};
  template <typename... Args> struct is_stl_container<std::deque             <Args...>>:std::true_type{};
  template <typename... Args> struct is_stl_container<std::list              <Args...>>:std::true_type{};
  template <typename... Args> struct is_stl_container<std::forward_list      <Args...>>:std::true_type{};
  template <typename... Args> struct is_stl_container<std::set               <Args...>>:std::true_type{};
  template <typename... Args> struct is_stl_container<std::multiset          <Args...>>:std::true_type{};
  template <typename... Args> struct is_stl_container<std::map               <Args...>>:std::true_type{};
  template <typename... Args> struct is_stl_container<std::multimap          <Args...>>:std::true_type{};
  template <typename... Args> struct is_stl_container<std::unordered_set     <Args...>>:std::true_type{};
  template <typename... Args> struct is_stl_container<std::unordered_multiset<Args...>>:std::true_type{};
  template <typename... Args> struct is_stl_container<std::unordered_map     <Args...>>:std::true_type{};
  template <typename... Args> struct is_stl_container<std::unordered_multimap<Args...>>:std::true_type{};
  template <typename... Args> struct is_stl_container<std::stack             <Args...>>:std::true_type{};
  template <typename... Args> struct is_stl_container<std::queue             <Args...>>:std::true_type{};
  template <typename... Args> struct is_stl_container<std::priority_queue    <Args...>>:std::true_type{};
}

//type trait to utilize the implementation type traits as well as decay the type
template <typename T> struct is_stl_container {
  static constexpr bool const value = is_stl_container_impl::is_stl_container<std::decay_t<T>>::value;
};

std::decay型修飾子に基づく誤った型推論を回避するためのの使用に注意してください。また、継承を利用std::true_typeし、タイプを自分std::false_typeで指定しないようにしました。::typeC ++ 11可変個引数テンプレートは、コンテナーの構築に必要なn個のテンプレートタイプパラメーターを推定するために使用されます。

実装の使用は、予想どおりです。

  std::cout << std::boolalpha;
  std::cout << is_stl_container<std::vector<int>>::value << '\n';
  std::cout << is_stl_container<std::vector<int>const&>::value << '\n';
  std::cout << is_stl_container<int>::value << '\n';

プリント:

true
true
false
于 2015-06-28T23:28:25.390 に答える
4

C ++ 20では、を使用できますconcept

コンテナと見なすものからチェックを追加するのはあなた次第ですが、次のようになります。

template <typename T>
concept Container = requires(T t)
{
    std::begin(t);
    std::end(t);
};

使用例

于 2020-12-15T14:41:39.327 に答える
2

is_containerブーストに はhttp://www.boost.org/doc/libs/1_51_0/libs/spirit/doc/html/spirit/advanced/customize/is_container.htmlがあります

is_container<C>::type---指定されたタイプCがコンテナとして扱われる場合はmpl::true_に評価されるメタ関数の結果、それ以外の場合はmpl :: false_一般に、is_containerの実装は、MPLブール値であるかのように動作する必要があります。絶え間ない..

于 2012-10-31T16:21:25.157 に答える
2

MSVC 2019でテスト済み:

template<class C>
struct IsContainer {
private:
    template<class D>
    static constexpr auto hasValueType() -> decltype(typename D::value_type(), std::true_type()) {
        return {};
    }

    template<class D>
    static constexpr auto hasIteratorAlias() -> decltype(typename D::iterator(), std::true_type()) {
        return {};
    }

    template<class D>
    static constexpr std::false_type hasIteratorAlias(...) {
        return {};
    }

    template<class D>
    static constexpr auto hasConstIteratorAlias() -> decltype(typename D::const_iterator(), std::true_type()) {
        return {};
    }

    template<class D>
    static constexpr auto hasBegin() -> decltype(decltype(std::begin(std::declval<D>())){}, std::true_type()) {
        return {};
    }

    template<class D>
    static constexpr std::false_type hasBegin(...) {
        return {};
    }

    template<class D>
    static constexpr auto hasEnd() -> decltype(decltype(std::end(std::declval<D>())){}, std::true_type()) {
        return {};
    }

    template<class D>
    static constexpr std::false_type hasEnd(...) {
        return {};
    }

    template<class D>
    static constexpr std::false_type hasConstIteratorAlias(...) {
        return {};
    }

    template<class D>
    static constexpr std::false_type hasValueType(...) {
        return {};
    }

public:
    constexpr static bool value = hasValueType<C>().value && 
        hasIteratorAlias<C>().value && 
        hasConstIteratorAlias<C>().value && 
        hasBegin<C>().value && 
        hasEnd<C>().value;
    
    constexpr bool operator()() const {
        return value;
    }
};

使用法:

std::vector<int> vec;
int x = 0;
float y = 0.f;
std::array<int, 1> arr{};
    
constexpr auto val = IsContainer<decltype(vec)>()();
constexpr auto val2 = IsContainer<decltype(x)>()();
constexpr auto val3 = IsContainer<decltype(y)>()();
constexpr auto val4 = IsContainer<decltype(arr)>()();
    
std::cout << static_cast<bool>(val) << '\n';
std::cout << static_cast<bool>(val2) << '\n';
std::cout << static_cast<bool>(val3) << '\n';
std::cout << static_cast<bool>(val4) << '\n';

出力:

1
0
0
1
于 2020-10-28T17:05:02.367 に答える
1

このコードは、コンテナの特性を定義します。もともとはprettyprintライブラリからのものです:

//put this in type_utils.hpp 
#ifndef commn_utils_type_utils_hpp
#define commn_utils_type_utils_hpp

#include <type_traits>
#include <valarray>

namespace common_utils { namespace type_utils {
    //from: https://raw.githubusercontent.com/louisdx/cxx-prettyprint/master/prettyprint.hpp
    //also see https://gist.github.com/louisdx/1076849
    namespace detail
    {
        // SFINAE type trait to detect whether T::const_iterator exists.

        struct sfinae_base
        {
            using yes = char;
            using no  = yes[2];
        };

        template <typename T>
        struct has_const_iterator : private sfinae_base
        {
        private:
            template <typename C> static yes & test(typename C::const_iterator*);
            template <typename C> static no  & test(...);
        public:
            static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
            using type =  T;

            void dummy(); //for GCC to supress -Wctor-dtor-privacy
        };

        template <typename T>
        struct has_begin_end : private sfinae_base
        {
        private:
            template <typename C>
            static yes & f(typename std::enable_if<
                std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::begin)),
                             typename C::const_iterator(C::*)() const>::value>::type *);

            template <typename C> static no & f(...);

            template <typename C>
            static yes & g(typename std::enable_if<
                std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::end)),
                             typename C::const_iterator(C::*)() const>::value, void>::type*);

            template <typename C> static no & g(...);

        public:
            static bool const beg_value = sizeof(f<T>(nullptr)) == sizeof(yes);
            static bool const end_value = sizeof(g<T>(nullptr)) == sizeof(yes);

            void dummy(); //for GCC to supress -Wctor-dtor-privacy
        };

    }  // namespace detail

    // Basic is_container template; specialize to derive from std::true_type for all desired container types

    template <typename T>
    struct is_container : public std::integral_constant<bool,
                                                        detail::has_const_iterator<T>::value &&
                                                        detail::has_begin_end<T>::beg_value  &&
                                                        detail::has_begin_end<T>::end_value> { };

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

    template <std::size_t N>
    struct is_container<char[N]> : std::false_type { };

    template <typename T>
    struct is_container<std::valarray<T>> : std::true_type { };

    template <typename T1, typename T2>
    struct is_container<std::pair<T1, T2>> : std::true_type { };

    template <typename ...Args>
    struct is_container<std::tuple<Args...>> : std::true_type { };

}}  //namespace
#endif

詳細については、私のブログ投稿を参照してください。

関連する質問:c++テンプレートクラス。任意のコンテナタイプで機能しますが、どのように定義しますか?

于 2016-06-05T09:41:46.003 に答える
0

簡単に言えば、C ++ 14を使用すると、STLおよびNON-STLの場合は次のようになります。

template<typename T>
constexpr bool is_container_v = std::is_same<decltype (std::declval<T>().begin()), decltype (std::declval<T>().end())>::value;
于 2021-10-30T08:21:26.330 に答える