【发布时间】:2014-04-12 12:17:53
【问题描述】:
我有一个像
这样的元组向量vector<tuple<T1, T2, T3>> v;
我相信,当元组类型的默认比较启动时,它会执行字典比较。
我可以按我选择的元素进行比较吗?例如,上面示例中的第二个元素或包含 m 类型的元组中的第 i 个元素?
提前谢谢你。
【问题讨论】:
我有一个像
这样的元组向量vector<tuple<T1, T2, T3>> v;
我相信,当元组类型的默认比较启动时,它会执行字典比较。
我可以按我选择的元素进行比较吗?例如,上面示例中的第二个元素或包含 m 类型的元组中的第 i 个元素?
提前谢谢你。
【问题讨论】:
有很多方法可以做到这一点,我使用的一种归结为声明一个自定义比较对象,实际上如下
// Functor to compare by the Mth element
template<int M, template<typename> class F = std::less>
struct TupleCompare
{
template<typename T>
bool operator()(T const &t1, T const &t2)
{
return F<typename tuple_element<M, T>::type>()(std::get<M>(t1), std::get<M>(t2));
}
};
它适用于任意长度的元组 (避免使用可变参数模板 - 尽管使用可变参数的方式相当容易和安全,因为您可以将 operator() 的参数声明为元组任意长度) 并且适用于对和您可以将自定义比较函数/对象传递给它,但使用< 运算符作为默认策略。一个示例用法是
int main()
{
vector<tuple<int, string>> v;
v.push_back(make_tuple(1, "Hello"));
v.push_back(make_tuple(2, "Aha"));
std::sort(begin(v), end(v), TupleCompare<0>());
return 0;
}
当然还有一种更现代的方法,使用 lambda,所以排序线是
std::sort(begin(v), end(v),
[](tuple<int, string> const &t1, tuple<int, string> const &t2) {
return get<0>(t1) < get<0>(t2); // or use a custom compare function
}
);
我相信为此创建一个函数对象是值得的(避免大量样板代码)并采用第一种方法
随着 Yakk 的评论(关于 c++1y)变得符合标准 (c++14),我们在下面演示 generic lambdas
的案例std::sort(begin(v), end(v), [](auto const &t1, auto const &t2) {
return get<0>(t1) < get<0>(t2); // or use a custom compare function
});
这与TupleCompare 的机制非常匹配,因为operator() 也是模板化的。
【讨论】:
std::tuple_element<M, T>::type 之前缺少typename
int? unsigned 或 std::size_t 可能会提供更好的诊断。哦,请注意 C++1y 使 lambda 案例超级简洁。
你可以这样做
#include <tuple>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
vector<tuple<int, float, char>> v;
int main() {
v.push_back(std::make_tuple(1,1.2,'c'));
v.push_back(std::make_tuple(1,1.9,'e'));
v.push_back(std::make_tuple(1,1.7,'d'));
sort(v.begin(),v.end(),
[](const tuple<int,float,char>& a,
const tuple<int,float,char>& b) -> bool
{
return std::get<1>(a) > std::get<1>(b);
});
cout << std::get<2>(v[0]) << endl;
return 0;
}
【讨论】:
是的,您可以在需要时在 C++ 中定义自定义排序。我想你需要它来处理std::sort,对吧?查看std::sort 的文档,准确地说是算法的第二个版本,即采用comp 参数的版本。
你必须定义一个小于函子,像这样:
struct CustomLessThan
{
bool operator()(tuple<T1, T2, T3> const &lhs, tuple<T1, T2, T3> const &rhs) const
{
return std::get<1>(lhs) < std::get<1>(rhs);
}
};
然后在std::sort中使用:
std::sort(v.begin(), v.end(), CustomLessThan());
在 C++11 中,您可以通过使用 lambda 而不是创建命名结构来使代码更短。 cppreference.com 上给出的示例也展示了这种技术。
【讨论】:
const 中的哪一个?给运营商自己的?这使得函数const 成为一个很好的实践。
const,无论是变量还是函数。只允许在真正需要的地方进行修改。对于具有相似概念的每种语言都是如此。不变性使代码更容易理解并且更稳定。例如,在 Java 中,最好将所有内容都设为final,直到/除非需要修改。不幸的是,Java 没有 final 方法。
所以这是我学会如何做的最简单的方法(我认为它比主要答案更直接)。这适用于元组中可以与< 进行比较的任何类型。
这里是排序函数TupleLess,它利用了一些C风格的语法:
#include <string>
#include <vector>
#include <tuple>
template<int index> struct TupleLess
{
template<typename Tuple>
bool operator() (const Tuple& left, const Tuple& right) const
{
return std::get<index>(left) < std::get<index>(right);
}
};
int main(){
//Define a Person tuple:
using Person = std::tuple<std::string, std::string, std::string>;
//Create some Person tuples and add to a vector
Person person1 = std::make_tuple("John", "Smith", "323 Fake Street");
Person person2 = std::make_tuple("Sheila", "Henrod", "784 Unreal Avenue");
Person person3 = std::make_tuple("Mitch", "LumpyLumps", "463 Falsified Lane");
std::vector<Person> vPerson = std::vector<Person>();
vPerson.push_back(person1);
vPerson.push_back(person2);
vPerson.push_back(person3);
//Sort by index at position 2
std::sort(vPerson.begin(), vPerson.end(), TupleLess<2>());
}
【讨论】: