2015-10-13 2 views
3

Я пытаюсь создать метод, который выбирает случайный элемент из типа контейнера, например std::vector. Раньше я использовал это:Получение типа из параметров шаблона шаблона

std::string pick_random(std::vector<std::string> c) { 
    int r = std::rand() % ids.size() + 1; 
    auto it = c.begin(); 
    std::advance(it, r); 
    return *it; 
} 

который, насколько я мог судить, работал нормально. Это не значит, что это отлично, только что это оказалось.

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

template <template<typename element_t> container_t> 
element_t pick_random(container_t from) { /* ... */ } 

Это, однако, выдает ошибку:

element_t does not name a type 

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

ответ

3

Еще лучше было бы, чтобы избежать произвольного ограничения на шаблонов классов. В конце концов, почему бы не выбрать элемент из необработанного массива? Для того, чтобы правильно назвать тип в C++ 11, мы должны были бы получить результат неквалифицированного вызова begin, которую мы можем получить с помощью:

namespace detail { 
    using std::begin; 

    template <typename C> 
    auto adl_begin(C&& c) -> decltype(begin(std::forward<C>(c))) { 
     return begin(std::forward<C>(c)); 
    } 
} 
using detail::adl_begin; 

И затем использовать , что вывести ELEMENT_TYPE из произвольного контейнера:

template <typename C> 
auto pick_random(C& container) -> decltype(*adl_begin(container)) 
{ /* rest as before */ } 

Side-примечание: возьмите контейнер по ссылке, а не по значению.

+0

Любой шанс, я могу получить объяснение для newb?Я не говорю, что я один, но ... ладно, да. –

+0

@QPaysTaxes То, что вы пытаетесь получить, - это получить контейнер, получить тип значения. Тип значения является результатом '* begin (container)' - поэтому это просто использует это напрямую, вместо того, чтобы пытаться «угадать» тип значения, разлагая тип контейнера. – Barry

+0

О, я вижу! Спасибо: D –

2

Если вы используете только стандартные библиотечные контейнеры, вы можете получить сохраненный тип из них, используя container_t::value_type.

template <typename container_t> 
typename container_t::value_type pick_random(container_t& container) 
{ ... } 
+1

Я думаю, что вы имели в виду 'container_t & container', потому что' C' нигде не определялся;) Кроме того, хороший ответ, но по какой-то досадной причине парень, который написал этот особый тип причудливого контейнера, не включал ': : value_type' –

6

container_t не является типом, container_t<T> есть.

Вы можете использовать следующее:

template <template<typename, typename...> C, typename T, typename...Ts> 
T pick_random(const C<T, Ts...>& from); 

за std::vector, у вас есть аллокатора: std::vector<T, Alloc>.

В C++ 14, вы можете просто использовать auto

template <typename C> 
auto pick_random(const C& from) { /* ... */ } 
+1

Почему использование OP элемента 'element_t' не распознается как тип? – jaggedSpire

5

Я не думаю, что здесь требуются «аргументы шаблона шаблона», вы могли бы просто использовать value_type из контейнера:

#include <iostream> 
#include <cstdlib> 
#include <ctime> 
#include <vector> 
#include <list> 

template <typename T> 
typename T::value_type pick_random(T& from) { 
    int r = std::rand() % from.size(); 
    auto it = from.begin(); 
    std::advance(it, r); 
    return *it; 
} 

int main() { 
    std::srand(std::time(0)); 

    std::vector<std::string> words {"the", "frogurt", "is", "also", "cursed"}; 
    std::list<int> numbers {1, 2, 3, 4, 5}; 

    std::cout << "words: " << pick_random(words) << std::endl; 
    std::cout << "numbers: " << pick_random(numbers) << std::endl; 
} 

value_type - the type of the values that can be obtained by dereferencing the iterator.

Source: http://en.cppreference.com/w/cpp/iterator/iterator_traits

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