template模板class,如果存在就调用一个函数

template template class, call a function if it exists

我有一个带有模板模板参数的简单函数。它的意思是采用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;
}

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

你看这里,所有这一切都是 push_backinput_container 到另一个的所有元素和 return.

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

container.reserve(input_container.size());

我该怎么做?

您可以使用重载

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

这是一个 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

检查class是否有储备功能:

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

std::enable_if 用于 C++03

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

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

除了 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);
}