2013-06-20 7 views
8

E 'possibile scrivere una classe tale che questi sono validi:Posso sovraccaricare un'inizializzazione implicita su 0?

Foo a; 
Foo b = 0; 
Foo c = b; 
Foo d(0); 
Foo e(1); 
Foo f = Foo(1); 

Ma questi non sono:

int x; 
Foo a = x; 
Foo b = 1; 
Foo c = 2; 
//etc 

In sostanza, la mia regola è "Una costante 0 è implicitamente convertibile in un Foo , ma nessun altro valore è "

+0

Che dire di 'Foo e (1);'? Come è valido? –

+0

@LuchianGrigore: Sono semanticamente identici? Se è così, immagino di poterlo dichiarare invalido. – Eric

+1

Forse puoi provare con un costruttore prendendo un 'std :: nullptr_t' (solo un'idea ...) –

risposta

5

Se non ti dispiace lavorare su Foo b = nullptr;, è piuttosto semplice effettuare l'hacking. Avere un costruttore esplicito da int e un implicito da std::nullptr_t.

Se pensi che funzioni, non sono sicuro che sia possibile. L'unico modo per distinguere tra un valore letterale di 0 e altri valori letterali interi è la conversione implicita del primo in puntatori e nullptr_t. Pertanto, nullptr preferirà un parametro nullptr_t a un parametro puntatore, pertanto, avendo entrambi i costruttori, è possibile filtrare gli argomenti nullptr. Tuttavia, le conversioni di 0 per i puntatori e nullptr_t sono dello stesso valore, quindi questo ucciderebbe gli argomenti 0 con un'ambiguità.

Hmm ... qualcosa come questo può funzionare:

class Foo { 
    struct dummy; 
public: 
    explicit Foo(int); // the version that allows Foo x(1); 
    Foo(dummy*); // the version that allows Foo x = 0; 
    template <typename T, 
      typename = typename std::enable_if< 
       std::is_same<T, std::nullptr_t>::value>::type> 
    Foo(T) = delete; // the version that prevents Foo x = nullptr; 
}; 

Non ho effettivamente provato questo. In teoria, il modello dovrebbe partecipare solo alla risoluzione di sovraccarico quando l'argomento è nullptr, perché altrimenti FINEE lo uccide. In tal caso, tuttavia, dovrebbe essere migliore del costruttore di puntatori.

0

Ca ca Un costruttore non esplicito di Foo che prende un int come argomento. Essenzialmente questa linea farà lo stesso cercando di convertire int a Foo usando questo costruttore int.

Foo b = 1; 

Non è possibile impedire che determinati valori di tale int vengano elaborati direttamente. Se si dispone del costruttore explicit, non sarà possibile scrivere anche la riga successiva.

Foo b = 0; 

gx_ ha dichiarato correttamente che 0 può essere convertito in std :: nullptr_t. Quanto segue funzionerà rispetto al tuo intento.

Foo(std::nullptr_t x) : member(0) { } 
explicit Foo(int c) : member(c) { } 
// ... 
Foo a = 0; // compiles 
Foo b = 1; // doesn't compile 

// Note: 
int do_stuff (void) { return 0; } 
Foo c = do_stuff(); // doesn't compile 
+0

No, inizializzazione diretta-copia. –

+1

Che ne dici di un 'esplicito Foo (int);' più un 'Foo (nullptr_t);'? –

+0

+1, Piuttosto pensato lateralmente ma possibile – Pixelchemist

-1

Un'idea che avevo era:

Foo(const uint32_t c) : member(0) { static_assert(c == 0, "Nope"); } 
explicit Foo(uint32_t c) : member(c) { } 

Questo comportarsi sensibilmente?

+2

Che non verrà nemmeno compilato. Per quanto riguarda la risoluzione di sovraccarico, un parametro 'const uint32_t' e un parametro' uint32_t' sono la stessa cosa. –

-1

ammetto che non ho raggiunto la completa padronanza della semantica rvalue di C++ ancora 11, ma questo sembra fare quello che vuoi:

class Foo 
{ 
    public: 
    Foo(int&&) {} 
}; 

int main() 
{ 
    Foo a(123); 
    int x = 123; 
    Foo b(x); // error here, line 11 
    return 0; 
} 

risultati:

prog.cpp:11: error: cannot bind ‘int’ lvalue to ‘int&&’

Commenti benvenuto, se questo codice ha qualche avvertenza che non ho notato, o se puoi rassicurarmi che non è così.

+0

Interessante, ma sto mirando al caso specifico di 'x == 0'; – Eric

+0

@eric Ah, non lo sapevo. Hai detto 'Foo e (1);' dovrebbe essere valido: / – Oktalist

Problemi correlati