I now want to make template that will push some elements to vectors and other types, that support push_back
operators.
I can do it like this
template<typename T>
T fill(size_t n) {
T v;
//(1)
for(size_t i = 0; i < n; ++i){
v.push_back(generate_some_how());
}
return v;
}
It works. But now I want to improve speed for types that support it using v.reserve(n);
instead of (1)
. But I want to still be able to compile this code for types that will not compile reserve
Is it some easy way to achieve this?
I know that I may specialize hard-coded types but it doesn't seem to be good.
C++11 is OK.
An easy example using C++11:
template<class T>
auto maybe_reserve(T& v, size_t n, int)
-> decltype(v.reserve(n), void())
{
v.reserve(n);
}
template<class T>
void maybe_reserve(T&, size_t, long){}
template<typename T>
T fill(std::size_t n) {
T v;
maybe_reserve(v, n, 0);
for(size_t i = 0; i < n; ++i){
v.push_back(generate_some_how());
}
return v;
}
Live example. For explanations, take a look here.
A possible approach in C++11:
template<typename T, typename = void>
struct reserve_helper
{ static void call(T& obj, std::size_t s) { } };
template<typename T>
struct reserve_helper<T, decltype(std::declval<T>().reserve(0), void(0))>
{ static void call(T& obj, std::size_t s) { obj.reserve(s); } };
template<typename T>
T fill(std::size_t n)
{
T v;
reserve_helper<T>::call(v, 10);
for(std::size_t i = 0; i < n; ++i){
v.push_back(generate_somehow());
}
return v;
}
Here is a live example showing that the call to reserve()
is simply skipped with a UDT that doesn't define any reserve()
member function.
Not too hard.... you need to write a trait that detects the presence of the reserve member function with the correct signature. With that tool in your belt there are different approaches, you can write a reserve_
template function that uses that trait to dispatch to either a call to reserve()
or a no-op and call it from // (1)
or you could use SFINAE either in the helper or the fill
itself. I would try to use a helper function as most of the code in fill is the same.
Detect if void reserve(std::size_t)
member function exists in C++03:
template <typename T>
struct has_reserve {
typedef char yes;
typedef yes no[2];
template <typename U, U> struct ptrmbr_to_type;
template <typename U>
static yes& test(ptrmbr_to_type<void (T::*)(std::size_t),&U::reserve>*);
template <typename U> static no& test(...);
static const bool value = sizeof(test<T>(0))==sizeof(yes);
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With