Ero curioso di sapere il motivo per cui questo pezzo di codice non funziona:namespace std sovraccarico meno di
#include "stdafx.h"
#include <iostream>
#include <tuple>
#include <string>
#include <vector>
#include <algorithm>
typedef std::tuple<int, std::string> intString;
bool operator<(intString& lhs, intString& rhs){
return std::tie(std::get<1>(lhs), std::get<0>(lhs)) < std::tie(std::get<1>(rhs), std::get<0>(rhs));
}
void printIntStrings(std::vector<intString>& v){
for (intString& i : v){
std::cout << std::get<0>(i) << " is " << std::get<1>(i) << std::endl;
}
}
int main(int argc, char* argv[])
{
std::vector<intString> v;
v.push_back(std::make_tuple(5, "five"));
v.push_back(std::make_tuple(2, "two"));
v.push_back(std::make_tuple(9, "nine"));
printIntStrings(v);
std::sort(v.begin(), v.end());
printIntStrings(v);
return 0;
}
Per quanto posso capire, ho semplicemente creare un vettore di intStrings e il mio operatore deve ordinare dal secondo elemento nella tupla primo quindi l'uscita dovrebbe essere (ultimi 3 linee comunque)
5 five
9 nine
2 two
Tuttavia esecuzione sulla mia macchina ottengo
2 two
5 five
9 nine
che implica che l'ordinamento utilizza l'operatore di default inferiore a, ignorando quello specificato. Nota, aggiungendo const prima che i parametri non sembrino influenzare nulla.
Ho trovato tre modi per "risolvere" questo.
Fix # 1
Surround bool operator < ... nel namespace std in questo modo:
namespace std{
bool operator<(intString& lhs, intString& rhs){
return std::tie(std::get<1>(lhs), std::get<0>(lhs)) < std::tie(std::get<1>(rhs), std::get<0>(rhs));
}
}
Tuttavia mi è stato detto che dovremmo mai aggiungere le cose al namespace std dal momento che il comportamento è indefinito, quindi questa correzione sembra la peggiore.
Fix # 2
Aggiungere in qualcosa di personalizzato alla tupla in questo modo:
enum class TRASH{DOESNTMATTER};
typedef std::tuple<int, std::string, TRASH> intString;
bool operator<(intString& lhs, intString& rhs){
return std::tie(std::get<1>(lhs), std::get<0>(lhs)) < std::tie(std::get<1>(rhs), std::get<0>(rhs));
}
(e, ovviamente, aggiungere TRASH :: doesntmatter come terzo argomento make_tuple) Tuttavia, questo sembrava come un sacco di lavoro per qualcosa di così semplice. Inoltre, sembra uno spreco poiché l'enum non è usato in modo significativo.
Fix # 3
utilizzare il predicato specie in questo modo:
std::sort(v.begin(), v.end(), operator<);
Questo sembrava essere la soluzione più elegante. Tuttavia, non vedo perché devo dire esplicitamente al compilatore di usare il mio operatore definito <.
Quindi vorrei sapere:
1) perché questo accade? Non dovrei C++ trovare la mia implementazione e usarla?
2) quale "fix" è il migliore? se nessuno di quelli che ho trovato, cosa consiglieresti?
Qualche idea? Grazie per aver letto!
Lo standard 'operator <' è una corrispondenza migliore perché i suoi parametri sono 'const'. – Oktalist
@Oktalist Oops, ho dimenticato di menzionare ma aggiungere cost prima che entrambi i parametri non siano d'aiuto. edit edit –
Il problema è che c'è _already_ un 'operator <' per le tuple, quindi il compilatore usa quello ufficiale piuttosto che il tuo hack. –