2010-02-18 4 views
6

Предположим, я хочу создать шаблонную функцию, которая возвращает первый элемент любого stl-контейнера. Общий способ:Как проверить, является ли параметр шаблона парой ассоциативных контейнеров?

template<typename Container> 
Container::value_type first(Container c){ 
    return *(c.begin()); 
} 

Это работает для векторов, списков, требований и т. Д.

Однако для пары ассоциативных контейнеров (станд :: карта), если хотели бы иметь

return c.begin()->second; 

Как я мог проверить (в функции или специализации шаблона), если у меня есть пара ассоциативный контейнер?

Контейнер STL, похоже, не имеет никаких признаков. Можно ли проверить, имеет ли он :: key_type?

ответ

3

Вы можете сделать довольно легко:

namespace result_of // pillaged from Boost ;) 
{ 
    template <class Value> 
    struct extract { typedef Value type; }; 

    template <class First, class Second> 
    struct extract < std::pair<First,Second> > { typedef Second type; }; 
} 

template <class Value> 
Value extract(Value v) { return v; } 

template <class First, class Second> 
Second extract(std::pair<First,Second> pair) { return pair.second; } 

template <class Container> 
typename result_of::extract< typename Container::value_type >::type 
first(const Container& c) { return extract(*c.begin()); } 

Я должен отметить, однако, что я, вероятно, добавить тест, чтобы увидеть, если контейнер empty ... Потому что, если контейнер empty, вы на для неопределенного поведения.

В движении:

int main(int argc, char* argv[]) 
{ 
    std::vector<int> vec(1, 42); 
    std::map<int,int> m; m[0] = 43; 
    std::cout << first(vec) << " " << first(m) << std::endl; 
} 

// outputs 
// 42 43 

примера беззастенчиво взяты из litb;)

+0

Хороший ответ. Чтобы получить его для компиляции, ';' отсутствуют в конце structs и .front() не работает для всего –

+0

Oups, это то, что вы получаете от ответа слишком быстро: я добавил отсутствующий ';' и заменил 'front' на разыменованные 'begin' :) –

3

Это один работает:

template<typename T> 
struct tovoid { 
    typedef void type; 
}; 

template<typename T, typename = void> 
struct value_type { 
    typedef typename T::value_type type; 
    static type get(T const& t) { 
    return *t.begin(); 
    } 
}; 

template<typename T> 
struct value_type<T, typename tovoid<typename T::mapped_type>::type> { 
    typedef typename T::mapped_type type; 
    static type get(T const& t) { 
    return t.begin()->second; 
    } 
}; 

template<typename Container> 
typename value_type<Container>::type first(Container const& c){ 
    return value_type<Container>::get(c); 
} 

int main() { 
    std::map<int, int> m; m[0] = 42; std::cout << first(m); 
    std::vector<int> a(1, 43); std::cout << first(a); 
} 

(выходы 4243)

1

Использовать специализацию функции шаблона:

template<typename Container> 
typename Container::value_type first(typename Container c) 
{ 
    return *(c.begin()); 
} 


template<typename K, typename V> 
typename V first(std::map<K,V> & c) 
{ 
    return c.begin()->second; 
} 
Смежные вопросы