我试图制作一个从容器类型中挑选随机元素的方法,例如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
我认为我的意图很清楚,但重申一下:我试图获取列表的元素类型。我可以有一个单独的模板参数,但是它无法正确推断出类型。我尝试了各种不同的版本,但都没有用。
答案 0 :(得分: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 :(得分: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
- 解除引用迭代器可以获得的值的类型。来源:http://en.cppreference.com/w/cpp/iterator/iterator_traits
答案 2 :(得分: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 */ }
附注:通过引用而不是值来获取容器。
答案 3 :(得分:2)
如果您只使用标准库容器,则可以使用container_t::value_type
从中获取存储的类型。
template <typename container_t>
typename container_t::value_type pick_random(container_t& container)
{ ... }