2015-12-29 8 views
16

Si consideri il seguente classe:Meno dell'operatore tramite conversione implicita?

struct C 
{ 
    /* Class contents, without any arithmetic operator... */ 
    constexpr operator int() noexcept; // Implicit conversion to int 
}; 

La mia domanda è:

  • è C utilizzabile in algoritmi standard come std::sort che attualmente utilizza il default dell'operatore <?
  • Il C è considerato soddisfacente al concetto LessThanComparable?
  • La C soddisfa i requisiti di un'ipotetica libreria di algoritmi concettualizzati che richiederebbe che il tipo sia LessThanComparable.
+1

Ero curioso e l'ho provato. Ho lavorato su C++ 14 qui: http://cpp.sh/4hdh –

risposta

12

È C utilizzabile in algoritmi standard come std::sort che attualmente utilizza l' < operatore predefinito?

Sì, funziona per std::sort() e alcuni altri algoritmi standard. Il codice

#include <algorithm> 
#include <vector> 

struct C 
{ 
    /* Class contents, without any arithmetic operator... */ 
    constexpr operator int() noexcept {return 0;} // Implicit conversion to int 
}; 

int main() 
{ 
    std::vector<C> v; 
    std::sort(begin(v), end(v)); 
} 

compila. Here's a live demo. Guarda però la prossima domanda!

È il C considerato soddisfacente il concetto LessThanComparable?

No. I requisiti del concetto LessThanComparable sono, che per gli oggetti x e y di tipo C o const C l'espressione x<y è valido e conversione implicita bool e l'operatore < stabilisce una stretta relazione debole ordinamento. Nel tuo caso, gli oggetti const non verranno convertiti in int s. Questo è un bug nel tuo codice, perché non è const corretto. L'aggiunta della parola chiave const funzionerà e la classe C sarà effettivamente LessThanComparable. Il severo rapporto di ordinamento debole è soddisfatto, perché gli standard int soddisfano questo requisito.

Will C soddisfare le esigenze di una ipotetica conceptified algoritmo biblioteca che richiedono il tipo di essere LessThanComparable.

Se si risolve il problema, sì, lo farà.

Poche note a margine:

  • GCC 4.9 compila x<y anche se x e y sono di tipo const C. Questo sembra essere un bug del compilatore, dal momento che GCC 5.2 e clang 3.6 generano un errore di compilazione qui.

  • Il passaggio di std::less<C>() come argomento aggiuntivo a std::sort() restituisce un errore di compilazione, in quanto la funzione di confronto richiede che gli oggetti costanti siano comparabili in quel caso. Tuttavia, passando std::less<void>() non si interrompe nulla, poiché gli argomenti vengono inoltrati perfettamente.

  • Il std::sort() algorithm non richiede un completo LessThanComparable, ma il concetto Compare. Inoltre, il tipo di iteratore deve essere un ValueSwappable e MoveAssignable. Questo è il caso della tua prima domanda, anche quando il bug di costanza non è corretto. Ecco perché lo std::sort() e altri algoritmi standard funzionano.

+1

Circa il primo punto: il fatto che il codice compili e funzioni in pratica non implica che tale comportamento sia richiesto dallo standard. – chi

+1

@chi Sono d'accordo. Ecco perché ho aggiunto un sidenote alla fine della mia risposta. Credo che tutte le implementazioni corrette dello standard debbano compilare il codice indicato. –

3

No. Il compilatore non può fare grandi magie, cioè chiamando il metodo cast e quindi applicando l'operatore <. Immagina che ci siano diversi operatori di cast per tipi diversi, come sceglierebbe il compilatore quello giusto?

MODIFICA: In realtà non è corretto. Finché c'è un solo operatore di cast, funzionerà. Ma con due o più il compilatore si lamenterà del cast ambiguo. Tuttavia, questo approccio è molto fragile, quindi in generale non è una buona idea.

+2

Non posso essere d'accordo con te, beh, non completamente. Il compilatore chiamerà il cast prima di applicare l'operatore. Ciò avverrà perché l'operatore è "solo una funzione" e se l'oggetto ha definito il metodo di lancio o il costruttore implicito con un argomento, verrà castato per abbinare questo operatore. L'ambiguità di diversi operatori di cast è un argomento completamente diverso. – Glapa

+0

@Glapa: hai ragione, ho controllato e ha funzionato. Finché non ho aggiunto un altro operatore di cast. Ho aggiornato la risposta però. –

+0

Voto positivo per la modifica. – ildjarn

2

Ho provato l'esempio proposto da mehrdad momeny. Ha funzionato bene. Tuttavia, con poche modifiche, non funziona più.

#include <iostream> 
#include <string> 
#include <vector> 
#include <algorithm> 

struct C 
{ 
    C(int x):X(x){} 
    operator int() { return X; } 
    operator float() { return static_cast<float>(X); } 

    int X; 
}; 

using namespace std; 

int main() 
{ 
    vector<C> u = {1, 2, 35, 6, 3, 7, 8, 9, 10}; 
    sort(u.begin(), u.end()); 
    for(auto x: u){ 
     cout << x << endl; 
    } 
} 

Live Demo

Poiché questo porterà ad un'ambiguità. Quindi, non è una buona idea farlo in questo modo.

+0

Quindi, è garantito che funzioni se esiste un solo operatore di conversione? – user2079303

+0

Non ho un indizio per questo, piuttosto che l'esempio di mehrdad momeny. Si dovrebbe scavare nello standard –