(Nota: tuple
e tie
pode ser obtido de Boost ou C ++ 11.)
Ao escrever pequenas estruturas com apenas dois elementos, às vezes tendo a escolher um std::pair
, pois todas as coisas importantes já foram feitas para esse tipo de dados, como operator<
para ordenação estrita-fraca .
As desvantagens, porém, são os nomes de variáveis praticamente inúteis. Mesmo que eu mesmo tenha criado isso typedef
, não vou me lembrar 2 dias depois o que first
e o que second
exatamente foi, especialmente se ambos forem do mesmo tipo. Isso fica ainda pior para mais de dois membros, já que aninhar pair
é uma droga.
A outra opção para isso é umtuple
, tanto do Boost quanto do C ++ 11, mas isso não parece nem um pouco melhor e mais claro. Portanto, volto a escrever as estruturas sozinho, incluindo quaisquer operadores de comparação necessários.
Uma vez que, especialmente, o operator<
pode ser bastante complicado, pensei em contornar toda essa bagunça apenas contando com as operações definidas para tuple
:
Exemplo de operator<
, por exemplo, para ordenação estrita-fraca:
bool operator<(MyStruct const& lhs, MyStruct const& rhs){
return std::tie(lhs.one_member, lhs.another, lhs.yet_more) <
std::tie(rhs.one_member, rhs.another, rhs.yet_more);
}
( tie
Faz uma tuple
das T&
referências dos argumentos passados.)
Edit : A sugestão de @DeadMG para herdar de forma privada tuple
não é ruim, mas tem algumas desvantagens:
- Se os operadores forem independentes (possivelmente amigos), preciso herdar publicamente
- Com a transmissão, minhas funções / operadores (
operator=
especificamente) podem ser facilmente contornados - Com a
tie
solução, posso deixar de fora determinados membros se eles não importarem para o pedido
Há alguma desvantagem nessa implementação que preciso considerar?
tie
não pode ser aplicada a membros de campo de bits.tie(...)
chamadas forem duplicadas em vários operadores (=, ==, <, etc.), você pode escrever um método inline privadomake_tuple(...)
para encapsular isso e, em seguida, chamá-lo de vários outros lugares, como emreturn lhs.make_tuple() < rhs.make_tuple();
(embora o tipo de retorno de esse método pode ser divertido de declarar!)auto tied() const{ return std::tie(the, members, here); }
Respostas:
Isso certamente tornará mais fácil escrever um operador correto do que fazer você mesmo. Eu diria que apenas consideraria uma abordagem diferente se a criação de perfil mostrar que a operação de comparação é uma parte demorada de seu aplicativo. Caso contrário, a facilidade de manutenção deve superar qualquer preocupação de desempenho possível.
fonte
tuple<>
'soperator<
seria mais lento do que um escrito à mão.Eu me deparei com esse mesmo problema e minha solução usa modelos variadic c ++ 11. Aí vem o código:
A parte .h:
E o .cpp para o caso base sem argumentos:
Agora seu exemplo se torna:
fonte
Na minha opinião, você ainda não está tratando do mesmo problema que as
std::tuple
soluções - ou seja, você tem que saber quantos e o nome de cada variável de membro, você está duplicando isso duas vezes na função. Você pode optar porprivate
herança.Essa abordagem é um pouco mais complicada para começar, mas você está apenas mantendo as variáveis e nomes em um lugar, em vez de em todos os lugares para cada operador que deseja sobrecarregar.
fonte
T& one_member(){ return std::get<0>(*this); }
etc? Mas isso não precisaria de mim para fornecer tal método para cada "membro" que tenho, incluindo sobrecargas para versões const e não const?Se você planeja usar mais de uma sobrecarga de operador ou mais métodos de tupla, recomendo tornar a tupla um membro da classe ou derivar dela. Caso contrário, o que você está fazendo é muito mais trabalhoso. Ao decidir entre os dois, uma pergunta importante a ser respondida é: Você quer que sua classe seja uma tupla? Se não, eu recomendaria conter uma tupla e limitar a interface usando delegação.
Você pode criar acessores para "renomear" os membros da tupla.
fonte
operator<
usandostd::tie
razoável?" Não entendo como essa resposta se relaciona a essa pergunta.