web-dev-qa-db-ja.com

型の特性「is_container」または「is_vector」を記述する方法は?

一般的なすべてのSTL構造(たとえば、vectorsetmap、...)に対して値がtrueであるタイプ特性を書き込むことは可能ですか?

はじめに、vectorの場合はtrue、それ以外の場合はfalseとなる型の特性を記述します。私はこれを試しましたが、コンパイルされません:

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;
};

エラーメッセージはtemplate parameters not used in partial specialization: U

27
Frank

STLのようなコンテナーを検出するための別のSFINAEベースのソリューション:

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 {};

もちろん、チェックするメソッドとタイプを変更することもできます。

STLコンテナーのみを検出する場合(つまり、std::vectorstd::listなど) this のようにする必要があります。

28
Nevermore

あなたはそれがそれよりも単純であるべきだと言うでしょう...

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;
};

...しかし、それがsimplerであるかどうかは本当にわかりません。

C++ 11では、型エイリアスを使用できます(テストされていないと思います)。

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

あなたのアプローチの問題は、型Uが、それが使用されているコンテキストでは推定できないことです。

実際、いくつかの試行錯誤の後、それは非常に簡単であることがわかりました。

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

より一般的なis_containerの書き方を知りたいです。すべてのタイプを手動でリストする必要がありますか?

13
Frank

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 { };
// ...

このようにして、ユーザーは部分的に特化することで独自のコンテナーを追加できます。 is_vector et-alについては、上記で行ったように部分的な特殊化を使用しますが、コンテナータイプは1つだけに制限し、多くは指定しません。

7
bstamour

クラスがコンテナであるかどうかを推測する他の答えはあなたのために働くかもしれませんが、私はあなたが真に返したいタイプに名前を付ける別の方法をあなたに提示したいと思います。これを使用して、任意のis_(something)特性タイプを構築できます。

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 {};

等々。

<type_traits>と、ルールに追加するクラスを含める必要があります。

7
Fozi

何かがコンテナであるかどうかを検出する方法は、data()およびsize()メンバー関数を探すことです。このような:

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 {};
2
Arvid
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 { };
1

2018年とC++ 17に早送りしました。@ Frankの答えを改善するのは大胆でした

// clang++ prog.cc -Wall -Wextra -std=c++17

 #include <iostream>
 #include <vector>

 namespace dbj {
    template<class T>
      struct is_vector {
        using type = T ;
        constexpr static bool value = false;
   };

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

  // and the two "olbigatory" aliases
  template< typename T>
     inline constexpr bool is_vector_v = is_vector<T>::value ;

 template< typename T>
    using is_vector_t = typename is_vector<T>::type ;

 } // dbj

   int main()
{
   using namespace dbj;
     std::cout << std::boolalpha;
     std::cout << is_vector_v<std::vector<int>> << std::endl ;
     std::cout << is_vector_v<int> << std::endl ;
}   /*  Created 2018 by [email protected]  */

"プディングプディング" 。これを行うにはより良い方法がありますが、これはstd::vector

1
user5560811

私たちのプロジェクトでは、C++ 11をサポートするコンパイラにまだ移行できなかったため、コンテナオブジェクトのtype_traitsについて、シンプルなブーストスタイルヘルパーを作成する必要がありました。

template<typename Cont> struct is_std_container: boost::false_type {};
template<typename T, typename A> 
struct is_std_container<std::vector<T,A> >: boost::true_type {};
template<typename T, typename A> 
struct is_std_container<std::list<T,A> >: boost::true_type {};
template<typename T, typename A> 
struct is_std_container<std::deque<T,A> >: boost::true_type {};
template<typename K, typename C, typename A> 
struct is_std_container<std::set<K,C,A> >: boost::true_type {};
template<typename K, typename T, typename C, typename A> 
struct is_std_container<std::map<K,T,C,A> >: boost::true_type {};

template<typename Cont> struct is_std_sequence: boost::false_type {};
template<typename T, typename A> 
struct is_std_sequence<std::vector<T,A> >: boost::true_type {};
template<typename T, typename A> 
struct is_std_sequence<std::list<T,A> >: boost::true_type {};
template<typename T, typename A> 
struct is_std_sequence<std::deque<T,A> >: boost::true_type {};
0
czarles

これをconst std :: vectorでも機能させるには、以下を使用できます。

namespace local {

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

template<typename T>
struct isVector<T,
        typename std::enable_if<
                std::is_same<typename std::decay<T>::type, std::vector<typename std::decay<T>::type::value_type, typename std::decay<T>::type::allocator_type> >::value>::type> : std::true_type {
};

}

TEST(TypeTraitTest, testIsVector) {
    ASSERT_TRUE(local::isVector<std::vector<int>>::value);
    ASSERT_TRUE(local::isVector<const std::vector<int>>::value);

    ASSERT_FALSE(local::isVector<std::list<int>>::value);
    ASSERT_FALSE(local::isVector<int>::value);

    std::vector<uint8_t> output;
    std::vector<uint8_t> &output2 = output;
    EXPECT_TRUE(core::isVector<decltype(output)>::value);
    EXPECT_TRUE(core::isVector<decltype(output2)>::value);
}

Std :: remove_cv呼び出しがないと、2番目のASSERT_TRUEは失敗します。しかし、もちろんこれはあなたのニーズに依存します。ここで重要なのは、仕様に従って、std :: is_sameがconstとvolatileも一致するかどうかをチェックすることです。

0
Martin Gerhardy