我有一个带模板模板参数的简单函数。它意味着采用一个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_back
从input_container
到另一个元素的所有元素并返回。
您可能已经注意到,如果输入为std::vector
,则O(1)
插入会出现性能问题,而std::list
和std::deque
则可以。所以我想做的是在循环之前调用它,如果可能的话(在编译时确定):
container.reserve(input_container.size());
我该怎么做?
答案 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);
}
答案 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);
}