2013-03-08 4 views
14

Теперь я хочу создать шаблон, который будет подталкивать некоторые элементы к векторам и другим типам, поддерживающим операторы 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

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

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

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

+0

Я сомневаюсь, но я не знаю точно. Я предполагаю, что вам придется использовать специализированную специализацию –

+4

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

+0

Если вы используете C++ 11, подумайте о поддержке соответствующего вызова 'emplace' для замены' push_back'. –

ответ

8

Простой пример использования 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. Для объяснения, посмотрите here.

+0

Возможно также версия C++ 03, хотя и более сложная и ограничительная. – Xeo

+0

не скомпилировался после изменения 'resize' в' reserve' для 'deque' [ideone] (http://ideone.com/e7p8fv) – RiaD

+0

@RiaD: Это проблема с GCC 4.7. Clang 3.2 и GCC 4.8 работают правильно. Ошибка GCC может быть изменена путем изменения возвращаемого типа первой перегрузки на 'decltype (v.reserve (n), void())'. – Xeo

2

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

Detect, если void reserve(std::size_t) функция член существует в 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); 
}; 
6

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

Вот live example показывает, что вызов reserve() просто пропускается с UDT, который не определяет какой-либо функции reserve() члена.

+0

Требуется, чтобы 'reserve' возвращал' void' (да, обычно это случай, я знаю). :) – Xeo

+0

@Xeo: Хорошо, все в порядке :) Позвольте мне отредактировать –

+1

Вы пытались скомпилировать и запустить это? : 3 – Xeo

Смежные вопросы