在编译时检查是模板类型向量

mkz*_*zwm 19 c++ templates

我可以想象以下代码:

template <typename T> class X
{
  public:
   T container;

   void foo()
   {
      if(is_vector(T))
         container.push_back(Z);
      else
         container.insert(Z);
   }
}

// somewhere else...

X<std::vector<sth>> abc;
abc.foo();
Run Code Online (Sandbox Code Playgroud)

如何编写,成功编译?我知道类型特征,但是当我定义时:

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 {};
Run Code Online (Sandbox Code Playgroud)

它不编译:

error: no matching function for call to 'std::vector<sth>::insert(Z)'
Run Code Online (Sandbox Code Playgroud)

static_assert也不是我想要的.有什么建议吗?

这是我想要实现的一个简短例子(SSCCE):http://ideone.com/D3vBph

gal*_*p1n 29

它被命名为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();
}
Run Code Online (Sandbox Code Playgroud)

  • 更好的是,调度的重载是私有的而不是公共的. (9认同)

Ze *_*lob 6

另一个值得考虑的方法是使用SFINAE检测push_back函数的存在.这稍微更通用,因为它将转换为实现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;
};
Run Code Online (Sandbox Code Playgroud)

请注意,它目前只检测push_back(const T&)而不是push_back(T&&).检测两者有点复杂.

以下是您如何利用它来实际插入.

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);
Run Code Online (Sandbox Code Playgroud)

老实说,这个解决方案比我原先预期的要复杂得多,所以除非你真的需要,否则我不会使用它.虽然它不是太难支持const T&T&&,它更神秘的代码,你必须保持这可能是不值得的,在大多数情况下.


小智 5

仅使用插入:

#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';
}
Run Code Online (Sandbox Code Playgroud)