Check at compile-time is a template type a vector

后端 未结 5 1632
死守一世寂寞
死守一世寂寞 2020-12-24 03:17

I can imagine the following code:

template  class X
{
  public:
   T container;

   void foo()
   {
      if(is_vector(T))
         contain         


        
相关标签:
5条回答
  • 2020-12-24 03:30

    If you use constexpr if, you were doing it right. This C++17 code compiles:

    #include <iostream>
    #include <type_traits>
    #include <vector>
    #include <list>
    
    template<typename T> struct is_vector : public std::false_type {};
    
    template<typename T, typename A>
    struct is_vector<std::vector<T, A>> : public std::true_type {};
    
    
    template <typename T>
    class X
    {
      public:
       T container;
    
       void foo()
       {
          if constexpr(is_vector<T>::value){
            std::cout << "I am manipulating a vector" << std::endl;
            // Can access container.push_back here without compilation error
          }
          else {
             std::cout << "I am manipulating something else" << std::endl;
          }
       }
    };
    
    int main() {
        X<std::vector<int>> abc;
        abc.foo(); // outputs "I am manipulating a vector"
    
        X<std::list<int>> def;
        def.foo(); // outputs "I am manipulating something else"
    }
    
    0 讨论(0)
  • 2020-12-24 03:34

    It is named tag dispatching :

    #include <vector>
    #include <set>
    #include <type_traits>
    
    template<typename T> struct is_vector : public std::false_type {};
    
    template<typename T, typename A>
    struct is_vector<std::vector<T, A>> : public std::true_type {};
    
    template <typename T>
    class X {
        T container;
    
        void foo( std::true_type ) {
            container.push_back(0);
        }
        void foo( std::false_type ) {
            container.insert(0);
        }
    public:
        void foo() {
            foo( is_vector<T>{} );
        }
    };
    
    // somewhere else...
    int main() {
        X<std::vector<int>> abc;
        abc.foo();
    
        X<std::set<int>> def;
        def.foo();
    }
    
    0 讨论(0)
  • 2020-12-24 03:49

    An alternative worth considering is to detect the presence of the push_back function using SFINAE. This is slightly more generic since it'll translate to other containers that implement push_back.

    template<typename T>
    struct has_push_back
    {
        template<typename U>
        static std::true_type test(
            decltype((void(U::*)(const typename U::value_type&)) &U::push_back)*);
    
        template<typename>
        static std::false_type test(...);
    
        typedef decltype(test<T>(0)) type;
        static constexpr bool value = 
            std::is_same<type, std::true_type>::value;
    };
    

    Note that it currently only detects push_back(const T&) and not push_back(T&&). Detecting both is a little more complicated.

    Here's how you make use of it to actually do the insert.

    template<typename C, typename T>
    void push_back_impl(C& cont, const T& value, std::true_type) {
        cont.push_back(value);
    }
    
    template<typename C, typename T>
    void push_back_impl(C& cont, const T& value, std::false_type) {
        cont.insert(value);
    }
    
    template<typename C, typename T>
    void push_back(C& cont, const T& value) { 
        push_back_impl(cont, value, has_push_back<C>::type());
    }
    
    std::vector<int> v;
    push_back(v, 1);
    
    std::set<int> s;
    push_back(s, 1);
    

    Honestly, this solution became a lot more complicated then I originally anticipated so I wouldn't use this unless you really need it. While it's not too hard to support const T& and T&&, it's even more arcane code that you have to maintain which is probably not worth it in most cases.

    0 讨论(0)
  • 2020-12-24 03:50

    Using insert only:

    #include <iostream>
    #include <vector>
    #include <set>
    
    template <typename T>
    class X
    {
        public:
        T container;
    
        template <typename U>
        void insert(const U& u) {
            container.insert(container.end(), u);
        }
    };
    
    int main() {
        X<std::vector<int>> v;
        v.insert(2);
        v.insert(1);
        v.insert(0);
    
        for(std::vector<int>::const_iterator pos = v.container.begin();
            pos != v.container.end();
            ++pos)
        {
            std::cout << *pos;
        }
        std::cout << '\n';
    
        X<std::set<int>> s;
        s.insert(2);
        s.insert(1);
        s.insert(0);
    
        for(std::set<int>::const_iterator pos = s.container.begin();
            pos != s.container.end();
            ++pos)
        {
            std::cout << *pos;
        }
        std::cout << '\n';
    }
    
    0 讨论(0)
  • 2020-12-24 03:50

    Here's the typical method using void_t:

    template <typename T>
    using void_t = void;  // C++17 std::void_t
    
    template <typename C, typename = void>  // I'm using C for "container" instead of T, but whatever.
    struct has_push_back_impl : std::false_type {};
    
    template <typename C>
    struct has_push_back_impl<C, void_t<decltype(std::declval<C>().push_back(typename C::value_type{}))>>
        : std::true_type {};  // Note that void_t is technically not needed in this case, since the 'push_back' member function actually returns void anyway, but it the general method to pass the type into void_t's template argument to obtain void.  For example, the 'insert' function from std::set and std::map do NOT return void, so 'has_insert' will need to use void_t.
    
    template <typename C>
    using has_push_back = has_push_back_impl<C>;  // void passed to the second template argument by default, thus allowing the second specialization to be used instead of the primary template whenever C has a push_back member function.
    

    This method will work for has_insert for associative containers, even though std::set, std::map's insert function return std::pair<typename T::iterator, bool> while std::multimap::insert returns std::multimap::iterator (this is one case where Ze Blob's method will not work).

    0 讨论(0)
提交回复
热议问题