用于对可变数量的数组进行排序的可变参数模板
variadic template for sorting variable number of arrays
我正在尝试编写一个程序,以使用可变参数模板将未排序的 'n' 向量排序为一个已排序的向量。它可以通过其他方式完成,但我想通过这种方式来更好地理解可变参数模板。我不知道我是否能做到这一点,但下面是我的尝试,但没有成功。
我的理解是最终 sorted_n_vector 将减少到 MergeVector<int> + MergeVector<int> + MergeVectorMergeVector<int>
与第 50 行相同(MergeVector a8(a5 + a6 + a7)) 但我认为这是错误的。请帮助并给我一些代码审查意见。
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <functional>
#include <string>
template<typename t>
class MergeVector {
public:
std::vector<t> arr_;
MergeVector(std::vector<t> arr) : arr_(arr) {}
auto operator + (MergeVector<t> &obj) {
std::vector<t> dst;
std::sort(arr_.begin(), arr_.end());
std::sort(obj.arr_.begin(), obj.arr_.end());
std::merge(arr_.begin(), arr_.end(), obj.arr_.begin(), obj.arr_.end(), std::back_inserter(dst));
MergeVector res(dst);
return res;
}
friend auto& operator<<(std::ostream &os, MergeVector<t>& mv)
{
std::copy(mv.arr_.begin(), mv.arr_.end(), std::ostream_iterator<t>(os, " "));
return os;
}
};
template<typename t>
auto sorted_n_vector(t vec)
{
return vec;
}
template<typename t, typename... vectors>
auto sorted_n_vector(t vec, vectors... args)
{
return vec + sorted_n_vector(args...);
}
int main() {
std::vector<int> a1 = {1, 2, 3};
std::vector<int> a2 = {4, 5, 6};
std::vector<int> a3 = {7, 8, 9};
MergeVector<int> a5(a1);
MergeVector<int> a6(a2);
MergeVector<int> a7(a3);
MergeVector<int> a8(a5 + a6 + a7); //---- Line 50
std::cout << a8 << std::endl;
#if 1
MergeVector<int> a9(sorted_n_vector(a5, a6, a7));
std::cout << a9 << std::endl;
#endif
return 0;
}
我遇到以下错误:
test.cpp:40:20: error: invalid operands to binary expression ('MergeVector<int>' and 'MergeVector<int>')
return vec + sorted_n_vector(args...);
~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:40:22: note: in instantiation of function template specialization 'sorted_n_vector<MergeVector<int>, MergeVector<int> >' requested here
return vec + sorted_n_vector(args...);
^
test.cpp:54:22: note: in instantiation of function template specialization 'sorted_n_vector<MergeVector<int>, MergeVector<int>, MergeVector<int> >' requested here
MergeVector<int> a9(sorted_n_vector(a5, a6, a7));
^
test.cpp:15:7: note: candidate function not viable: expects an l-value for 1st argument
auto operator + (MergeVector<t> &obj) {
sorted_n_vector
有一个 return 类型指定为 auto
,因此它将 return 一个临时对象,而不是对其他对象的引用。
您尝试使用此临时参数调用 operator+
,但 operator+
需要非常量(左值)引用参数。
禁止将临时变量(或更确切地说是右值表达式)绑定到非常量(左值)引用,因此编译器不会考虑调用您的 operator+
,而是会在其他地方搜索。
找不到 +
的任何替代调用,它会向您提供您所看到的错误消息。
解决方法是将operator+
的参数作为const引用:
auto operator + (const MergeVector<t> &obj) {
将临时变量(右值表达式)绑定到 const(左值)引用是允许的,并且可以按预期工作。
编辑:
但是这会引发另一个错误,因为您的 operator+
实际上是在修改 obj
和 this
。虽然您可以通过按值而不是按引用获取参数来解决此问题,但这是一种不寻常的设计。通常 +
不应修改其参数。如果 c = a+b
失败,那将是令人惊讶的,因为 a
或 b
不允许被修改。您可以通过在 MergeVector
构造函数中进行排序来实现此目的:
MergeVector(std::vector<t> arr) : arr_(arr) {
std::sort(arr_.begin(), arr_.end());
}
然后你可以在 operator+
中删除 std::sort
行,你可以在两个参数中完全 const
:
auto operator + (const MergeVector<t> &obj) const {
将 operator+()
声明为成员函数是个坏主意。它适用于 operator+=()
但 operator+()
更适合作为 friend
函数。
举例
friend auto operator+ (MergeVector<t> mv1, MergeVector<t> mv2)
{
std::vector<t> dst;
std::sort(mv1.arr_.begin(), mv1.arr_.end());
std::sort(mv2.arr_.begin(), mv2.arr_.end());
std::merge(std::make_move_iterator(mv1.arr_.begin()),
std::make_move_iterator(mv1.arr_.end()),
std::make_move_iterator(mv2.arr_.begin()),
std::make_move_iterator(mv2.arr_.end()),
std::back_inserter(dst));
return MergeVector<t>{dst};
}
观察到,现在您按值传递参数(以避免编译器错误,如 uneven_mark 所述),您可以使用移动语义(参见 std::make_move_iterator
的使用).
我知道在您的示例中您只使用整数,并且对于如此简单的类型移动语义没有用。但是如果编写模板代码,你应该尝试想象更复杂的用例。
额外建议:鉴于您在构造函数中按值传递数组,您应该在其中使用移动语义
MergeVector (std::vector<t> arr) : arr_{std::move(arr)} {}
奖金观察:如果你能使用C++17,你就可以使用模板折叠,所以
template<typename... vectors>
auto sorted_n_vector(vectors... args)
{
return (args + ...);
}
我正在尝试编写一个程序,以使用可变参数模板将未排序的 'n' 向量排序为一个已排序的向量。它可以通过其他方式完成,但我想通过这种方式来更好地理解可变参数模板。我不知道我是否能做到这一点,但下面是我的尝试,但没有成功。
我的理解是最终 sorted_n_vector 将减少到 MergeVector<int> + MergeVector<int> + MergeVectorMergeVector<int>
与第 50 行相同(MergeVector a8(a5 + a6 + a7)) 但我认为这是错误的。请帮助并给我一些代码审查意见。
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <functional>
#include <string>
template<typename t>
class MergeVector {
public:
std::vector<t> arr_;
MergeVector(std::vector<t> arr) : arr_(arr) {}
auto operator + (MergeVector<t> &obj) {
std::vector<t> dst;
std::sort(arr_.begin(), arr_.end());
std::sort(obj.arr_.begin(), obj.arr_.end());
std::merge(arr_.begin(), arr_.end(), obj.arr_.begin(), obj.arr_.end(), std::back_inserter(dst));
MergeVector res(dst);
return res;
}
friend auto& operator<<(std::ostream &os, MergeVector<t>& mv)
{
std::copy(mv.arr_.begin(), mv.arr_.end(), std::ostream_iterator<t>(os, " "));
return os;
}
};
template<typename t>
auto sorted_n_vector(t vec)
{
return vec;
}
template<typename t, typename... vectors>
auto sorted_n_vector(t vec, vectors... args)
{
return vec + sorted_n_vector(args...);
}
int main() {
std::vector<int> a1 = {1, 2, 3};
std::vector<int> a2 = {4, 5, 6};
std::vector<int> a3 = {7, 8, 9};
MergeVector<int> a5(a1);
MergeVector<int> a6(a2);
MergeVector<int> a7(a3);
MergeVector<int> a8(a5 + a6 + a7); //---- Line 50
std::cout << a8 << std::endl;
#if 1
MergeVector<int> a9(sorted_n_vector(a5, a6, a7));
std::cout << a9 << std::endl;
#endif
return 0;
}
我遇到以下错误:
test.cpp:40:20: error: invalid operands to binary expression ('MergeVector<int>' and 'MergeVector<int>')
return vec + sorted_n_vector(args...);
~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:40:22: note: in instantiation of function template specialization 'sorted_n_vector<MergeVector<int>, MergeVector<int> >' requested here
return vec + sorted_n_vector(args...);
^
test.cpp:54:22: note: in instantiation of function template specialization 'sorted_n_vector<MergeVector<int>, MergeVector<int>, MergeVector<int> >' requested here
MergeVector<int> a9(sorted_n_vector(a5, a6, a7));
^
test.cpp:15:7: note: candidate function not viable: expects an l-value for 1st argument
auto operator + (MergeVector<t> &obj) {
sorted_n_vector
有一个 return 类型指定为 auto
,因此它将 return 一个临时对象,而不是对其他对象的引用。
您尝试使用此临时参数调用 operator+
,但 operator+
需要非常量(左值)引用参数。
禁止将临时变量(或更确切地说是右值表达式)绑定到非常量(左值)引用,因此编译器不会考虑调用您的 operator+
,而是会在其他地方搜索。
找不到 +
的任何替代调用,它会向您提供您所看到的错误消息。
解决方法是将operator+
的参数作为const引用:
auto operator + (const MergeVector<t> &obj) {
将临时变量(右值表达式)绑定到 const(左值)引用是允许的,并且可以按预期工作。
编辑:
但是这会引发另一个错误,因为您的 operator+
实际上是在修改 obj
和 this
。虽然您可以通过按值而不是按引用获取参数来解决此问题,但这是一种不寻常的设计。通常 +
不应修改其参数。如果 c = a+b
失败,那将是令人惊讶的,因为 a
或 b
不允许被修改。您可以通过在 MergeVector
构造函数中进行排序来实现此目的:
MergeVector(std::vector<t> arr) : arr_(arr) {
std::sort(arr_.begin(), arr_.end());
}
然后你可以在 operator+
中删除 std::sort
行,你可以在两个参数中完全 const
:
auto operator + (const MergeVector<t> &obj) const {
将 operator+()
声明为成员函数是个坏主意。它适用于 operator+=()
但 operator+()
更适合作为 friend
函数。
举例
friend auto operator+ (MergeVector<t> mv1, MergeVector<t> mv2)
{
std::vector<t> dst;
std::sort(mv1.arr_.begin(), mv1.arr_.end());
std::sort(mv2.arr_.begin(), mv2.arr_.end());
std::merge(std::make_move_iterator(mv1.arr_.begin()),
std::make_move_iterator(mv1.arr_.end()),
std::make_move_iterator(mv2.arr_.begin()),
std::make_move_iterator(mv2.arr_.end()),
std::back_inserter(dst));
return MergeVector<t>{dst};
}
观察到,现在您按值传递参数(以避免编译器错误,如 uneven_mark 所述),您可以使用移动语义(参见 std::make_move_iterator
的使用).
我知道在您的示例中您只使用整数,并且对于如此简单的类型移动语义没有用。但是如果编写模板代码,你应该尝试想象更复杂的用例。
额外建议:鉴于您在构造函数中按值传递数组,您应该在其中使用移动语义
MergeVector (std::vector<t> arr) : arr_{std::move(arr)} {}
奖金观察:如果你能使用C++17,你就可以使用模板折叠,所以
template<typename... vectors>
auto sorted_n_vector(vectors... args)
{
return (args + ...);
}