C++中的模板和高阶类型
Templates and higher-order kinds in C++
我正在尝试编写一个函数,该函数接受两个相同包含类型的容器,例如,两个std::vector<int>
,或者一个std::list<int>
和一个std::vector<int>
。(但不是std::vector<int>
和std::vector<double>
!
由于我不太确定应该如何完成,我决定先编写一个测试程序:
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
struct vector_wrapper
{
template <typename T>
struct instance_wrapper
{
typedef typename std::vector<T> instance;
};
};
struct list_wrapper
{
template <typename T>
struct instance_wrapper
{
typedef typename std::list<T> instance;
};
};
template <typename T, typename C1, typename C2>
void move(typename C1::instance_wrapper<T>::instance& c1, typename C2::instance_wrapper<T>::instance& c2) // line 29
{
while (c1.size() > 0)
{
c2.push_front(c1.back());
c1.pop_back();
}
}
int main()
{
std::vector<int> v;
std::list <int> l;
v.reserve(10);
for (int i = 0; i < 10; ++i)
v.push_back(i);
move<int, vector_wrapper, list_wrapper>(v, l);
std::for_each(l.begin(), l.end(),
[] (int i) { std::cout << i << " "; }
);
std::cout << std::endl;
return 0;
}
这段代码使用 -std=c++11
标志在 g++ 4.7 中给了我以下编译时错误:
metaclass.cpp:29:24: error: non-template 'instance_wrapper' used as template
... more ...
为什么编译器不能正确标识instance_wrapper
模板?
已经告诉你出了什么问题(来自 ideone 的错误):
prog.cpp:25:24:错误:非模板"instance_wrapper"用作模板
prog.cpp:25:24:注意:使用"C1::模板instance_wrapper"来指示它是一个模板
使用 C1::template instance_wrapper
而不是 C1::instance_wrapper
- 同样,对C2::instance_wrapper
执行相同的操作:
template <typename T, typename C1, typename C2>
void move(typename C1::template instance_wrapper<T>::instance& c1,
typename C2::template instance_wrapper<T>::instance& c2)
{
// ...
这是因为C1
是模板,编译器无法推断instance_wrapper
是模板并将其视为非模板类型。
请,请阅读编译器输出的所有内容。不仅仅是一行一行。编译器通常会在前面或后面的行中说出什么问题,就像在这种情况下,当它已经给你答案时!
这是一个更好的解决方案,它不需要任何禁用参数推导并让客户端指定它们的奇怪包装器,只需在 C++03 中工作的干净简单的 SFINAE:
#include <type_traits> // or Boost equivalent
// a little helper struct to keep the
// function as clutter-free as possible
template<class C1, class C2, class T = void>
struct enable_if_same_value_type
: std::enable_if<std::is_same<typename C1::value_type,
typename C2::value_type>::value, T>
{
};
template<class C1, class C2>
typename enable_if_same_value_type<C1, C2>::type
move(C1& source, C2& target){
/* ... */
}
请注意,你的代码不是很通用的,顺便说一句,因为push_front
不受std::vector
支持,所以你永远无法传递其中的两个。另外,我不会move
调用该函数,因为您将第一个容器的内容预置在第二个容器上。
也就是说,C++11 中有一个std::move
重载,它采用三个迭代器,并将第一个迭代器标记的内容移动到作为第三个参数传递的输出迭代器中。因此,可以按如下方式重写main
:
#include <algorithm> // algorithmic move
#include <vector>
#include <list>
#include <iterator> // front_inserter
#include <iostream>
int main(){
std::vector<int> v;
std::list<int> l;
v.reserve(10);
for (unsigned i = 0; i < 10; ++i)
v.push_back(i);
// I used 'rbegin' and 'rend' so the order stays the same
std::move(v.rbegin(), v.rend(), std::front_inserter(l));
std::copy(l.begin(), l.end(), std::ostream_iterator<int>(std::cout, " "));
}
Ideone上的活生生的例子。
为了将来参考,您可以更简单地执行此操作:
#include <type_traits>
template<typename T, typename A1, typename A2, template <typename, typename> class Cont1, template<typename, typename> class Cont2>
void move(Cont1<T, A1>& from, Cont2<T, A2>& to) {
while (!from.empty()) { // use !empty(), not size()
to.push_front(from.back());
from.pop_back();
}
}
std::vector<int> v;
std::list<int> l;
move(v, l); // and no need to specify types
- C++高阶模板
- C++:实现一个接收lambda作为输入的高阶函数
- 调用 lambda 时出现分段错误,从 C++11 中的高阶函数返回
- C++无法派生高阶函数的模板参数
- 模板参数扣除/替换使用Lambda表达式使用高阶函数失败
- 使用std ::函数或转发引用作为高阶函数的通用对象输入参数
- 更高态类型的别名模板
- 高阶沃罗诺伊图
- 创建高阶映射函数时,应该使用指针、引用或值
- C++中的模板和高阶类型
- 初学者:我应该从高阶还是低阶开始
- 我可以使用来自不同类的函数参数创建一个高阶函数吗?
- 应用于数组的高阶函数
- _mm_cvtsd_f64高阶浮点的类似物
- 提升元函数类高阶函数
- 这两个高阶函数定义之间有什么区别吗?
- C++的高阶函数
- 大变量的高阶贝塞尔函数计算
- 具有模板的高阶函数
- 如何用c++模板模拟高阶函数