简体   繁体   English

std::vector 上的模板特化<T>

[英]template specialization on std::vector<T>

I'm trying to write a template function that will handle any type of argument, including vectors, maps etc, but I'm having trouble.我正在尝试编写一个模板函数来处理任何类型的参数,包括向量、映射等,但我遇到了麻烦。

template<class C>
void foo(C c);

template<>
template<class V>
void foo<std::vector<V> >(std::vector<V> v);

The compiler (g++ 4.9.2-10) will complain about this:编译器 (g++ 4.9.2-10) 会抱怨这个:

test.cpp:13:43: error: too many template parameter lists in declaration of ‘void foo(std::vector<V>)’
 void foo<std::vector<V> >(std::vector<V> v) {
                                           ^
test.cpp:13:6: error: template-id ‘foo<std::vector<V> >’ for ‘void foo(std::vector<V>)’ does not match any template declaration
 void foo<std::vector<V> >(std::vector<V> v) {
      ^
test.cpp:13:43: note: saw 2 ‘template<>’, need 1 for specializing a member function template
 void foo<std::vector<V> >(std::vector<V> v) {
                                           ^

How can I achieve this?我怎样才能做到这一点? I also want to specialize on std::map<std::string, V>我也想专攻 std::map<std::string, V>

removing the first template<> line from the specialization still doesn't work (illegal specialization)从专业化中删除第一个 template<> 行仍然不起作用(非法专业化)

You cannot partially specialize a function, you want to create a new overload:你不能部分特化一个函数,你想创建一个新的重载:

template <class C>
void foo(C c);

template <class V>
void foo(std::vector<V> v); // This is a different overload, not a specialization!

Please note the difference with a partial specialization of foo :请注意与foo的部分特化的区别:

template <class C>
void foo(C c); // 1

template <class V>
void foo<std::vector<V>>(std::vector<V> v); // 2

Here 2 is a partial specialization of 1 , which is not allowed in C++ for function.这里2是的部分特1 ,这是不是在C ++允许对功能。

You may find it convenient to overload on the basis of the traits of the container.您可能会发现根据容器的特性进行重载很方便。

This allows a little more flexibility in terms of accepting references, const references and r-value references while only writing the function once.这在接受引用、常量引用和右值引用方面提供了更多的灵活性,同时只编写一次函数。

Here is a small example which implements a template foo for anything which has a begin() and an end() method, except for std::strings, which gets its own version of foo via a non-template overload:这是一个小示例,它为任何具有begin()end()方法的东西实现了模板foo ,除了 std::strings,它通过非模板重载获取自己的foo版本:

#include <vector>
#include <map>
#include <iostream>
#include <iomanip>

// trait type to determine whether something models a range.
template<class T>
struct is_range
{
    template <class Y> static auto has_begin(T*p) -> decltype(p->begin(), void(), std::true_type());
    template <class Y> static auto has_begin(...) -> decltype(std::false_type());

    template <class Y> static auto has_end(T*p) -> decltype(p->end(), void(), std::true_type());
    template <class Y> static auto has_end(...) -> decltype(std::false_type());

    static constexpr bool value = decltype(has_begin<T>(0))::value && decltype(has_end<T>(0))::value;
};


// specialised mini-functor for dealing with corner cases
template<class T>
struct emitter
{
    std::ostream& operator()(std::ostream& os, const T& t) const {
        return os << t;
    }
};

template<class T, class U>
struct emitter<std::pair<T, U>>
{
    std::ostream& operator()(std::ostream& os, const std::pair<T, U>& p) const
    {
        return os << "(" << p.first << ", " << p.second << ")";
    }
};

// a version of foo which works for all known containers, whether temporararies or references
template<class Container,
std::enable_if_t<is_range<std::decay_t<Container>>::value and not std::is_same<std::decay_t<Container>, std::string>::value>* = nullptr
>
void foo(Container&& c)
{
    // do things with c.begin(), c.end()
    bool first = true;
    for (auto& x : c) {
        using emitter_type = emitter<std::decay_t<decltype(x)>>;
        auto emit = emitter_type();
        if (first) {
            first = false;
        } else {
            std::cout << ", ";
        }
        emit(std::cout, x);
    }
    std::cout << std::endl;
}

// overload for std string

void foo(const std::string& s)
{
    std::cout << std::quoted(s) << std::endl;
}

int main()
{
    using namespace std::literals;

    foo(std::map<std::string, std::string> {
        {
            { { "foo" }, { "bar" } },
            { { "aaaa" }, { "bbbbb" } }
        }
    });
    foo(std::vector<std::string> {
        { "foo" },
        { "bar" },
        { "xxxx" },
        { "yyyy" } });

    foo("hello"s);

}

expected output:预期输出:

(aaaa, bbbbb), (foo, bar)
foo, bar, xxxx, yyyy
"hello"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM