Как проверить, является ли параметр шаблона парным ассоциативным контейнером? - PullRequest
6 голосов
/ 18 февраля 2010

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

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

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

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

return c.begin()->second;

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

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

Ответы [ 3 ]

3 голосов
/ 18 февраля 2010

Это работает:

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)

3 голосов
/ 18 февраля 2010

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

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

1 голос
/ 18 февраля 2010

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

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...