I am fairly new to std::tuple and std::tie. I need a way to efficiently order structs according to a left to right ordering of comparisons. For this reason, I chose to use the std::make_tuple and std::tie types for custom ordering a StructA in the live example provided. The tuple approach provides built in equivalence comparisons starting from left to right which is ideal for LessThanComparable element ordering for a std::sort with an accompanying lambda comparator (for which I show 3 examples).
The problem is that as far as I am aware, std::make_tuple makes inefficient copies of the tuple elements, and I was wondering if there was some way to combine std::make_tuple with std::tie as I tried to do with my 3rd comparator - which failed (otherwise its output would look like the first output ordering).
In my specific example I cannot use std::tie directly as I need to use a temporary as the 1st element in my tuple.
The output is as follows
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
I was expecting that the 3rd set of outputs would be identical to the first or alternatively if someone could tell me how to correctly mix inefficient std::tuples with efficient 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, ""));
}