从模板模板方法参数获取类型

时间:2015-10-13 19:01:20

标签: c++ templates c++11

我试图制作一个从容器类型中挑选随机元素的方法,例如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

我认为我的意图很清楚,但重申一下:我试图获取列表的元素类型。我可以有一个单独的模板参数,但是它无法正确推断出类型。我尝试了各种不同的版本,但都没有用。

4 个答案:

答案 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)
{ ... }