std::vector<T> 的模板专业化
template specialization on std::vector<T>
我正在尝试编写一个模板函数来处理任何类型的参数,包括向量、地图等,但我遇到了麻烦。
template<class C>
void foo(C c);
template<>
template<class V>
void foo<std::vector<V> >(std::vector<V> v);
编译器 (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) {
^
我怎样才能做到这一点?
我还想专注于 std::map
从专业化中删除第一个 template<> 行仍然不起作用(非法专业化)
你不能部分特化一个函数,你想创建一个新的重载:
template <class C>
void foo(C c);
template <class V>
void foo(std::vector<V> v); // This is a different overload, not a specialization!
请注意 foo
:
偏特化的区别
template <class C>
void foo(C c); // 1
template <class V>
void foo<std::vector<V>>(std::vector<V> v); // 2
这里 2
是 1
的部分特化,这在 C++ 中不允许用于函数。
大家可能会觉得根据容器的特性进行重载很方便
这在接受引用、const 引用和 r 值引用方面允许更多的灵活性,同时只编写一次函数。
这是一个小例子,它为任何具有 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);
}
预期输出:
(aaaa, bbbbb), (foo, bar)
foo, bar, xxxx, yyyy
"hello"
我正在尝试编写一个模板函数来处理任何类型的参数,包括向量、地图等,但我遇到了麻烦。
template<class C>
void foo(C c);
template<>
template<class V>
void foo<std::vector<V> >(std::vector<V> v);
编译器 (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) {
^
我怎样才能做到这一点?
我还想专注于 std::map
从专业化中删除第一个 template<> 行仍然不起作用(非法专业化)
你不能部分特化一个函数,你想创建一个新的重载:
template <class C>
void foo(C c);
template <class V>
void foo(std::vector<V> v); // This is a different overload, not a specialization!
请注意 foo
:
template <class C>
void foo(C c); // 1
template <class V>
void foo<std::vector<V>>(std::vector<V> v); // 2
这里 2
是 1
的部分特化,这在 C++ 中不允许用于函数。
大家可能会觉得根据容器的特性进行重载很方便
这在接受引用、const 引用和 r 值引用方面允许更多的灵活性,同时只编写一次函数。
这是一个小例子,它为任何具有 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);
}
预期输出:
(aaaa, bbbbb), (foo, bar)
foo, bar, xxxx, yyyy
"hello"