2013-04-19 2 views
1

В этой статье Traits: a new and useful template technique, черты были введены черты в C++ впервые, и автор подчеркивает следующее:В каких ситуациях параметры, используемые для создания шаблона, недоступны?

template <class numT> 
class matrix { 
public: 
    typedef numT num_type; 
    typedef float_traits<num_type> traits_type; 
    inline num_type epsilon() { return traits_type::epsilon(); } 
    ... 
}; 

Обратите внимание, что во всех примерах, до сих пор, каждый шаблон предоставляет государственные typedef S из его параметров, и и все, что от них зависело. Это не случайно: в самых разных ситуациях параметры, используемые для создания экземпляра шаблона, недоступны и могут быть получены только в том случае, если они указаны в объявлении шаблона как typedef. Мораль: всегда предоставляйте эти typedefs.

Но меня смущает то, что ситуация не показана, если необходимо использовать typedef. Может ли кто-нибудь объяснить это?

ответ

1

простой пример:


Рассмотрим вы хотите написать общую функцию сумма, которая суммирует все элементы в STL container. Это может быть vector, list или set.А содержание может быть int 's, float' s или string «s (для строк сумма будет конкатенация) (для простоты).

Если контейнер содержит int «S, то сумма будет int. Если он содержит floats то сумма не будет int но вы точку floating. А для strings это должно быть string. Everyhing остальное то же самое (операции внутри функции.)


Один способ написать это будет

template<typename T> 
T sum(const vector<T>& t) { 
    T total = T(); 
    // iterate and sum. 
    return total; 
} 

, но проблема в том, что теперь вам нужно написать эту функцию для каждого тип контейнера (set, list, ..). Так что на самом деле это не так.


Чтобы быть более общим вам нужно будет написать что-то вроде этого

template<typename T> 
?? sum(const T& t) { 
    ?? total; 
    // iterate and sum. 
    return ?? 
} 

но что вернуться сюда ?. Как вы узнаете, что содержит контейнер. Вот где находятся typedefs. В контейнерах Lucky STL есть несколько typedefs, которые могут дать вам некоторое представление о том, что они делают и способны делать. Для нашего случая они определили Содержится типа, как value_type (я уверен, вы использовали C::iterator в какой-то момент, который также является ЬурейеЕ).


Теперь наша маленькая функция сумма может быть записана в виде

template<typename T> 
typename 
T::value_type sum(const T& t) { 
    typedef typename T::value_type v_type;; 
    v_type total = v_type(); 
    // iterate and sum. 
    return total; 
} 

Вообще это хорошая идея, чтобы переадресовать типов шаблонов с typdefs. Например, если вы разрабатываете шаблон класса C с двумя типами шаблонов T и V

template<typename T, typename V> 
class C { 
    typedef T t_type; 
    typedef V v_type; 
    // 
    // 
} 

Это будет полезно для кого-то с помощью C.Они могут легко найти, с какими типами T и V сделал объект c типа C получить набран.

+0

+1, но для использования вами 'value_type' требуется' typename', потому что они являются зависимыми от шаблона именами типов. (Пример без имени типа: http://ideone.com/JVBlBy; пример с: http://ideone.com/EbCbr1) –

+0

@BillyONeal о да. Спасибо. – stardust

+0

(Erm мои примеры сосут, потому что я не инициализировал общее количество, ну хорошо) –

4

Допустим, у вас есть шаблон функции, которая принимает универсальный контейнер T:

template <typename ContainerT> 
void DoThings(ContainerT const& input) 
{ 
    // Do something 
} 

В этом методе, вы хотите, чтобы получить итератор к чему-то в контейнере. Но вы не знаете тип итератора; вы только дали тип контейнера, а не итератора:

template <typename ContainerT> 
void DoThings(ContainerT const& input) 
{ 
    /* ??? */ it = input.begin(); 
} 

Скажем, ради аргумента, что вы могли бы решить эту проблему, и вы хотели разыменования итератора. Чтобы сохранить результат, вам необходимо знать, что такое T; но это вызывает та же проблема снова:

template <typename ContainerT> 
void DoThings(ContainerT const& input) 
{ 
    /* ??? */ it = input.begin(); 
    /* ??? */ firstElement = *it; 
} 

Мы не знаем, что T, тип, содержащийся в контейнере; у нас есть только тип самого контейнера в этом шаблоне функции. Чтобы получить тип внутри контейнера, нам нужен контейнер, чтобы немного помочь нам и рассказать нам, что это за его тип. Класс контейнера делает это через typedef. Для стандартных контейнеров, это было бы iterator для типа итератора и value_type для типа содержащегося значения:

template <typename ContainerT> 
void DoThings(ContainerT const& input) 
{ 
    // Container provides its iterator type via a typedef. 
    typename ContainerT::iterator it = input.begin(); 

    // Container provides its contained type via a typedef. 
    typename ContainerT::value_type firstElement = *it; 
} 

Даже в C++ 11, где можно было бы решить приведенный выше пример с auto:

template <typename ContainerT> 
void DoThings(ContainerT const& input) 
{ 
    // Make the compiler figure it out: 
    auto it = input.begin(); 
    auto firstElement = *it; 
} 

иногда вы все еще хотите, чтобы иметь возможность получить фактический тип для других целей:

// Failure to compile: http://ideone.com/vxJ2IU 
// Successful compile: http://ideone.com/b5fU3S 
#include <vector> 
#include <list> 
#include <deque> 
#include <type_traits> 
#include <iostream> 

template <typename ContainerT> 
void DoThings(ContainerT const& input) 
{ 
    // DoThings only accepts integral containers: 
    static_assert(
     std::is_integral<typename ContainerT::value_type>::value, 
     "DoThings requires that the contained type be integral"); 
    // Make the compiler figure it out: 
    auto it = input.begin(); 
    auto firstElement = *it; 
    std::cout << firstElement; 
} 

int main() 
{ 
    std::vector<int> abc; 
    abc.push_back(42); 

    std::list<long> def; 
    def.push_back(1729); 

    std::deque<short> queue; 
    queue.push_back(1234); 

    DoThings(abc); 
    DoThings(def); 
    DoThings(queue); 

    // Does not compile due to static assert: 
    std::vector<double> doubles; 
    doubles.push_back(3.14); 
    DoThings(doubles); 
} 
Смежные вопросы