模板模板类,如果存在则调用函数

时间:2017-04-10 07:28:21

标签: c++ c++11 templates stl template-templates

我有一个带模板模板参数的简单函数。它意味着采用一个STL容器,将智能ptr转换为普通的ptr(它是一个C ++ 03项目,但我也对C ++ 11的答案感兴趣):

template <template <typename _T, typename = std::allocator<_T> > class Container>
static Container<T*> GetRawPtrContainer(const Container<SmartPtr<T> >& input_container)
{
    Container<T*> container;
    for(typename Container<SmartPtr<T> >::const_iterator it = input_container.begin();
        it != input_container.end();
        it++)
    {
        container.push_back(it->ptr);
    }
    return container;
}

这是类SmartPtr<T>的静态成员函数。

您在此处看到,所有这一切都是push_backinput_container到另一个元素的所有元素并返回。

您可能已经注意到,如果输入为std::vector,则O(1)插入会出现性能问题,而std::liststd::deque则可以。所以我想做的是在循环之前调用它,如果可能的话(在编译时确定)

container.reserve(input_container.size());

我该怎么做?

4 个答案:

答案 0 :(得分:4)

检查类是否具有保留功能:

C ++ 03:

template<typename T> struct HasReserve {
    struct Fallback { void reserve(size_t); };
    struct Derived : T, Fallback { };

    template<typename C, C> struct Check;

    template<typename C> static char(&f(Check<void (Fallback::*)(size_t), &C::reserve>*))[1];
    template<typename C> static char(&f(...))[2];

    static bool const value = sizeof(f<Derived>(0)) == 2;
};

C ++ 11:

template <typename T, typename = int>
struct HasReserve : std::false_type { };

template <typename T>
struct HasReserve <T, decltype(&T::reserve, 0)> : std::true_type { };

尽可能调用reserve的函数:

template<typename T>
typename std::enable_if<HasReserve<T>::value>::type
    Reserve(T& container, size_t s)
{
    container.reserve(s);
}

template<typename T>
typename std::enable_if<!HasReserve<T>::value>::type
Reserve(T&, size_t)
{
}

只需在循环之前调用Reserve函数,它应该像你想要的那样工作。

template <template <typename _T, typename = std::allocator<_T> > class Container>
static Container<T*> GetRawPtrContainer(const Container<SmartPtr<T> >& input_container)
{
    Container<T*> container;
    Reserve(container, input_container.size()); // just add this to your function
    for(typename Container<SmartPtr<T> >::const_iterator it = input_container.begin();
        it != input_container.end();
        it++)
    {
        container.push_back(it->ptr);
    }
    return container;
}

用于C ++ 03的std :: enable_if

template<bool B, class T = void>
struct enable_if {};

template<class T>
struct enable_if<true, T> { typedef T type; };

答案 1 :(得分:1)

您可以使用重载

// Common code in general template and specialization
template <template <typename _T, typename = std::allocator<_T> > class Container>
static Container<T*> GetRawPtrContainer(const Container<SmartPtr<T> >& input_container,Container<T*> &container)
{
    for(typename Container<SmartPtr<T> >::const_iterator it = input_container.begin();
        it != input_container.end();
        it++)
    {
        container.push_back(it->ptr);
    }
    return container;
}

// General template
template <template <typename _T, typename = std::allocator<_T> > class Container>
static Container<T*> GetRawPtrContainer(const Container<SmartPtr<T> >& input_container)
{
    Container<T*> container;
    return GetRawPtrContainer(input_container,container);
}

//Vector specialization
template <template <typename _T>
static Container<T*> GetRawPtrContainer(const std::vector<SmartPtr<T> >& input_container)
{
    std::vector<T*> container;
    container.reserve(input_container.size());
    return GetRawPtrContainer(input_container,container);
}

答案 2 :(得分:0)

这是一个C ++ 11实现,它与容器无关,并且在输入容器具有.reserve成员函数的情况下保留缓冲区。

template<typename Container, typename T>
auto 
insert(Container& container, T &&v, int) ->
decltype(container.push_back(std::forward<T>(v)), void()) {
  container.push_back(std::forward<T>(v));
}

template<typename Container, typename T>
void
insert(Container &container, T &&v, ...) {
  container.insert(std::forward<T>(v));
}

template<typename T, template<typename...> class Container>
auto
GetRawPtrContainer_helper(Container<T> const &container, int) -> 
decltype(container.reserve(42), Container<typename T::element_type*>()) {

  Container<typename T::element_type*> out;
  out.reserve(container.size());
  for(auto &&e : container) insert(out, e.get(), 0);

  return out;
}

template<typename T, template<typename...> class Container>
Container<typename T::element_type*>
GetRawPtrContainer_helper(Container<T> const &container, ...) {

  Container<typename T::element_type*> out;
  for(auto &&e : container) insert(out, e.get(), 0);

  return out;
}

template<typename T, template<typename...> class Container>
Container<typename T::element_type*>
GetRawPtrContainer(Container<T> const &container) {

  return GetRawPtrContainer_helper(container, 0);
}

Live Demo

答案 3 :(得分:0)

除了ACB的解决方案之外,请注意,您还可以使用constexpr和traits调度(C ++ 17),从而允许具有复杂的constexpr条件:

template <typename T, typename = int>
struct HasReserve : std::false_type {
};

template <typename T>
struct HasReserve<T, decltype(&T::reserve, 0)> : std::true_type {
};

template<typename T>
inline constexpr void reserve(T& container, size_t s)
{
    if constexpr (HasReserve<T>::value)
        container.reserve(s);
}