Функция вызова, если есть, игнорировать иначе - программирование
Подтвердить что ты не робот

Функция вызова, если есть, игнорировать иначе

Теперь я хочу создать шаблон, который будет подталкивать некоторые элементы к векторам и другим типам, поддерживающим операторы push_back.

Я могу сделать это вот так:

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

Это работает. Но теперь я хочу улучшить скорость для типов, которые поддерживают его, используя v.reserve(n); вместо (1). Но я хочу по-прежнему скомпилировать этот код для типов, которые не будут компилироваться reserve

Это простой способ достичь этого?

Я знаю, что я могу специализировать жестко кодированные типы, но это не кажется хорошим.

С++ 11 в порядке.

4b9b3361

Ответ 1

Простой пример с использованием С++ 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;
}

Живой пример. Для пояснений посмотрите здесь.

Ответ 2

Возможный подход в С++ 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;
}

Вот живой пример, показывающий, что вызов reserve() просто пропускается с UDT, который не работает 't определить любую функцию члена reserve().

Ответ 3

Не слишком сложно.... вам нужно написать признак, который обнаруживает наличие функции-члена резерва с правильной подписью. С помощью этого инструмента в вашем поясе существуют разные подходы, вы можете написать функцию шаблона reserve_, которая использует эту черту для отправки на вызов reserve() или no-op и вызывать его из // (1), или вы можете использовать SFINAE либо в помощнике, либо в самом fill. Я бы попытался использовать вспомогательную функцию, так как большая часть кода в заполнении одинакова.

Определить, существует ли функция-член void reserve(std::size_t) в С++ 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);
};