【发布时间】:2014-07-01 19:58:27
【问题描述】:
我对 std::tuple 和 std::tie 还很陌生。我需要一种根据从左到右的比较顺序有效地对结构进行排序的方法。出于这个原因,我选择使用std::make_tuple 和std::tie 类型在提供的live example 中自定义订购一个StructA。元组方法提供了从左到右的内置等价比较,这对于带有 lambda 比较器的 std::sort 的 LessThanComparable 元素排序非常理想(为此我展示了 3 个示例)。
问题是,据我所知,std::make_tuple 使 inefficient copies 成为元组元素,我想知道是否有某种方法可以将 std::make_tuple 与 std::tie 结合起来,就像我尝试的那样用我的第三个比较器做 - 它失败了(否则它的输出看起来像第一个输出排序)。
在我的具体示例中,我不能直接使用 std::tie,因为我需要使用临时元素作为元组中的第一个元素。
输出如下
Order[mPath.filename(), elem1, intVal]
======================================
"/zoo/dir1/filename.txt" - nameA1 - 1
"/tmp/dir1/filename.txt" - nameA1 - 3
"/fad/dir1/filename.txt" - nameA1 - 4
Order[mPath, elem1, intVal]
======================================
"/fad/dir1/filename.txt" - nameA1 - 4
"/tmp/dir1/filename.txt" - nameA1 - 3
"/zoo/dir1/filename.txt" - nameA1 - 1
Order[mPath.filename(), elem1, intVal]
======================================
"/fad/dir1/filename.txt" - nameA1 - 4
"/tmp/dir1/filename.txt" - nameA1 - 3
"/zoo/dir1/filename.txt" - nameA1 - 1
我期待第三组输出与第一组相同,或者如果有人能告诉我如何正确混合低效的 std::tuples 和高效的 std::ties
#include <iostream>
#include <string>
#include <vector>
#include <tuple>
#include <boost/filesystem.hpp>
struct StructA {
boost::filesystem::path mPath;
std::string elem1;
int intVal;
};
template<typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, StructA const& sa) {
return os << sa.mPath << " - " << sa.elem1 << " - " << sa.intVal << std::endl;
}
int main()
{
std::vector<StructA> aStructs = {
{"/zoo/dir1/filename.txt", "nameA1", 1},
{"/fad/dir1/filename.txt", "nameA1", 4},
{"/tmp/dir1/filename.txt", "nameA1", 3}
};
std::cout << "Order[mPath.filename(), elem1, intVal]" << std::endl;
std::cout << "======================================" << std::endl;
std::sort(aStructs.begin(), aStructs.end(),
[](const StructA& lhs, const StructA& rhs){
return std::make_tuple(lhs.mPath.filename(), lhs.elem1, lhs.intVal) <
std::make_tuple(rhs.mPath.filename(), rhs.elem1, rhs.intVal);
});
// print reordered structs
std::copy(aStructs.begin(), aStructs.end(),
std::ostream_iterator<StructA>(std::cout, ""));
std::cout << std::endl;
std::cout << "Order[mPath, elem1, intVal]" << std::endl;
std::cout << "======================================" << std::endl;
std::sort(aStructs.begin(), aStructs.end(),
[](const StructA& lhs, const StructA& rhs){
return std::tie(lhs.mPath, lhs.elem1, lhs.intVal) <
std::tie(rhs.mPath, rhs.elem1, rhs.intVal);
});
// print reordered structs
std::copy(aStructs.begin(), aStructs.end(),
std::ostream_iterator<StructA>(std::cout, ""));
std::cout << std::endl;
std::cout << "Order[mPath.filename(), elem1, intVal]" << std::endl;
std::cout << "======================================" << std::endl;
std::sort(aStructs.begin(), aStructs.end(),
[](const StructA& lhs, const StructA& rhs){
// attempt at efficiency - but not quite right
return lhs.mPath.filename() < rhs.mPath.filename() &&
std::tie(lhs.elem1, lhs.intVal) < std::tie(rhs.elem1, rhs.intVal);
});
// print reordered structs
std::copy(aStructs.begin(), aStructs.end(),
std::ostream_iterator<StructA>(std::cout, ""));
}
【问题讨论】:
-
您仍然可以使用
std::tie和一些as_lvalue,例如stackoverflow.com/q/23566857/420683 -
将来自
filename()调用的返回值分配给局部变量,然后使用std::tie。不是一个非常可扩展的解决方案,但当您只处理 2 个此类变量时也不错。 -
@johnco3 我的意思是
auto f1 = lhs.mPath.filename(); auto f2 = rhs.mPath.filename(); return std::tie(f1, lhs.elem1, lhs.intVal) < std::tie(f2, rhs.elem1, rhs.intVal); -
@Praetorian - 太棒了 - 这就是我正在寻找的答案!干得好!
标签: c++ sorting c++11 stl boost-tuples