我有一个课程模板。在这个类模板中,我试图定义一个成员函数模板,它在string集合上接受string,集合本身可以是任何类型的StdLib集合,但实际上它要么是vector,要么是list。
因为集合可以是任何类型,所以我使用一个template-template参数来指定集合类型。但是,它始终是string的集合。我希望模板参数演绎能够工作,这样我就不必在调用成员函数时指定集合类型。
下面的SSCCE代码类似于我的预期用例。
到目前为止,我已经对类定义(现场演示)进行了如下操作:
template <typename Foo>
struct Gizmo
{
Foo mF;
Gizmo (Foo f) : mF (f) {};
template <template <typename> class Cont> void DoIt(
typename Cont <string>::const_iterator begin,
typename Cont <string>::const_iterator end)
{
stringstream ss;
ss << "(" << this->mF << ")\n";
const std::string s = ss.str();
copy (begin, end, ostream_iterator <std::string> (cout, s.c_str()));
}
};类模板实例化的编译成功:
int main()
{
list <string> l;
l.push_back ("Hello");
l.push_back ("world");
Gizmo <unsigned> g (42);
}然而,当我试图利用论点推断(没有它,整个练习几乎毫无意义):
g.DoIt (l.begin(), l.end());GCC抱怨说,它无法推断模板参数:
prog.cpp: In function ‘int main()’:
prog.cpp:34:28: error: no matching function for call to ‘Gizmo<unsigned int>::DoIt(std::list<std::basic_string<char> >::iterator, std::list<std::basic_string<char> >::iterator)’
g.DoIt (l.begin(), l.end());
^
prog.cpp:34:28: note: candidate is:
prog.cpp:16:49: note: template<template<class> class typedef Cont Cont> void Gizmo<Foo>::DoIt(typename Cont<std::basic_string<char> >::const_iterator, typename Cont<std::basic_string<char> >::const_iterator) [with Cont = Cont; Foo = unsigned int]
template <template <typename> class Cont> void DoIt(
^
prog.cpp:16:49: note: template argument deduction/substitution failed:
prog.cpp:34:28: note: couldn't deduce template parameter ‘template<class> class typedef Cont Cont’
g.DoIt (l.begin(), l.end());最终,我真正关心的是能够在一个string集合上使用开始迭代器和结束迭代器调用string。实际的集合类型可以是vector或list,我不想指定模板参数,也不想基于容器重载。
我怎么才能让这个起作用?
注意,我的实际用例将在C++03中。C++11解决方案是受欢迎的,但我只能接受C++03解决方案。
发布于 2014-02-03 18:37:52
有几个问题。我为您修复了模板参数。我还修改了方法签名,以便您可以自动推断类型,但它需要传入原始集合:
#include <iostream>
#include <vector>
#include <list>
#include <string>
#include <sstream>
#include <iterator>
using namespace std;
template <typename Foo>
struct Gizmo
{
Foo mF;
Gizmo (Foo f) : mF (f) {};
template <template <typename T, typename A = allocator<T> > class Cont> void DoIt(
const Cont <string> &, // deduction
const typename Cont <string>::iterator &begin,
const typename Cont <string>::iterator &end)
{
stringstream ss;
ss << "(" << this->mF << ")\n";
const std::string s = ss.str();
copy (begin, end, ostream_iterator <std::string> (cout, s.c_str()));
}
};
int main()
{
list <string> l;
l.push_back ("Hello");
l.push_back ("world");
Gizmo <unsigned> g (42);
g.DoIt (l, l.begin(), l.end());
}看它跑到这里来。
发布于 2014-02-03 19:05:42
我好像没抓住重点,但你为什么不能这么做呢?
template <typename Iterator> void DoIt(
Iterator begin,
Iterator end)
{
// snip
}
// [...]
list <string> l;
l.push_back ("Hello");
l.push_back ("world");
vector <string> v;
v.push_back ("Hello");
v.push_back ("world");
Gizmo <unsigned> g (42);
g.DoIt (l.begin(), l.end());
g.DoIt (v.begin(), v.end());发布于 2014-02-04 05:42:43
我认为您实际上并不关心您的输入是vector,还是list,甚至是容器。我认为您真正关心的是,您有一系列可以迭代的东西,可以转换为string。因此,您应该接受其value_type is_convertible to string (在Coliru现场演示)的任何迭代器:
template <typename Iter>
typename enable_if<
is_convertible<
typename iterator_traits<Iter>::value_type,string
>::value
>::type DoIt(Iter begin, Iter end) const
{
stringstream ss;
ss << "(" << this->mF << ")\n";
const std::string s = ss.str();
copy (begin, end, ostream_iterator <std::string> (cout, s.c_str()));
}我对约束的丑陋表示歉意,概念Lite不能很快到达这里。
https://stackoverflow.com/questions/21534181
复制相似问题