使用模板模板参数扣除参数
argument deduction with template template parameters
我有一个类模板。在此类模板中,我试图定义一个成员函数模板,该模板在string
s的集合中接受const_iterator
s。该集合本身可以是任何类型的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
集合中使用始终和结束迭代器调用DoIt
。实际类型的集合可以是vector
或list
,我不想指定模板参数,也不想基于容器过载。
我该如何工作?
请注意,我的实际用例将在C 03中。欢迎C 11解决方案,但我只能接受C 03解决方案。
有几个问题。我为您修复了模板模板参数。我还修改了方法签名,以便您可以自动推论类型,但是它需要传递原始集合:
#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());
}
看到它在这里运行。
似乎我错过了重点,但是你为什么不能这样做?
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());
我提交您实际上不在乎您的输入是vector
还是list
,甚至是容器。我认为您实际上所关心的只是您可以迭代的一系列内容,这些内容可转换为string
。因此,您应该接受value_type
is_convertible
到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对我来说无法尽快到达这里。
问题是,对于非const字符串begin
和end
函数返回string::iterator
,而不是string::const_iterator
。您应该仅使用string::iterator
编写类似的功能。或者,在C 11中,您可以使用CBEGIN和CEND函数。
这是一个未偿还的上下文,您无法处理。
给定一个迭代器,您只是无法分辨它属于哪种容器。原始指针可以简单地用作多种容器的迭代器。
幸运的是,您永远不会将容器类型用于任何东西,因此您可以将其扔掉并在迭代器上进行参数化。
,但我确实使用它来确保我的容器包含字符串!
不,你没有。谁告诉您Foo<string>::iterator
对字符串(或者就此存在)的dere键?当然,如果存在,它可能会 becsuse becsuse over现有惯例,但这绝不可以保证。
- 如何反转整数参数包
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用默认参数等选择模板专业化
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 函数调用中参数的顺序重要吗
- 部分定义/别名模板模板参数
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- 使用不带参数的函数访问结构元素
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 如何使用Luacneneneba API正确读取字符串和表参数
- 在派生函数中指定void*参数
- 视图中的参数推导失败:take_while
- static_assert在宏中,但也可以扩展到可以用作函数参数的东西
- 使用指向成员的指针将成员函数作为参数传递
- 没有名称的C++模板参数
- 如何将enable-if与模板参数和参数包一起使用