2015-09-29 14 views
11

In C++ 11, c'è un modo pulito per disabilitare la conversione implicita tra typedef, o devi fare qualcosa di brutto come avvolgere il tuo int in una classe e definire ed eliminare vari operatori?Disabilita conversione implicita tra typedef

typedef int Foo; 
typedef int Bar; 
Foo foo(1); 
Bar bar(2); 
bar = foo; // Implicit conversion! 
+3

typedef non sono tipi reali, sono solo abbreviazioni o alias per i tipi reali. – Barmar

+0

Quindi 'foo' e' bar' sono in realtà lo stesso tipo e non ci sono conversioni. – Barmar

+0

Sì, è chiaro. Ma il C++ moderno ha un rimpiazzo che crea un nuovo tipo senza un mazzo di piastre? –

risposta

5

Lo standard C++ dice:

7.1.3 Il typedef specificatore

Un nome dichiarato con lo specificatore typedef diventa un nome-typedef. Nell'ambito della sua dichiarazione, un typedef-name è sintatticamente equivalente a una parola chiave e nomina il tipo associato all'identificatore in come descritto nella Clausola 8. Un nome typedef è quindi un sinonimo per un altro tipo. Un nome-typedef non non introduce un nuovo tipo il modo in cui una dichiarazione di classe (9.1) o di dichiarazione enum fa

Ma per esempio class o struct introdurre nuovi tipi. Nell'esempio seguente, uniqueUnused non viene utilizzato per creare un diverso tipo Value<int, 1> != Value<int, 2>. Quindi forse questo è qualcosa che stai cercando. Ricorda che non c'è alcuna garanzia che il compilatore si liberi della struttura esterna! L'unica garanzia di questo codice ti dà è la stessa dimensione di int

template<typename T, int uniqueUnused> 
struct Value 
{ 
    Value() : _val({}) {} 
    Value(T val) : _val(val) { } 
    T _val; 
    operator T&() { return _val; } 

    // evaluate if you with or without refs for assignments 
    operator T() { return _val; } 
}; 

using Foo = Value<int, 1>; 
using Bar = Value<int, 2>; 
static_assert(sizeof(Foo) == sizeof(int), "int must be of same size"); 
static_assert(sizeof(Bar) == sizeof(int), "int must be of same size"); 

Se si desidera creare un nuovo tipo basato su una classe si può semplicemente andare con questo esempio (questo non funziona con i tipi scalari dal non si può ereditare da interi):

class Foo : public Bar // introduces a new type called Foo 
{ 
    using Bar::Bar; 
}; 
5

HelloWorld spiega perché quello che hai non può funzionare. Avrai bisogno di ciò che in genere viene definito "forte" typedef per fare ciò che desideri. Un esempio di implementazione è BOOST_STRONG_TYPEDEF:

#include <boost/serialization/strong_typedef.hpp>  

BOOST_STRONG_TYPEDEF(int, a) 
void f(int x); // (1) function to handle simple integers 
void f(a x); // (2) special function to handle integers of type a 
int main(){ 
    int x = 1; 
    a y; 
    y = x;  // other operations permitted as a is converted as necessary 
    f(x);  // chooses (1) 
    f(y);  // chooses (2) 
} 

Se avessimo fatto typedef int a;, allora il codice sarebbe ambiguo.

+0

Anche bello. 'BOOST_STRONG_TYPEDEF' introduce anche un wrapper o è gratuito? – HelloWorld

+0

@HelloWorld "' BOOST_STRONG_TYPEDEF' è una macro che genera una classe denominata "nome" che racchiude un'istanza del suo tipo primitivo e fornisce operatori di conversione appropriati per rendere il nuovo tipo sostituibile a quello da esso ". – Barry

+0

@HelloWorld Inoltre ** ha ** di introdurre un wrapper, per i motivi che fornisci nella risposta :) – Barry

-1

Non è rigoroso controllo tipo, ma conversioni illegali può fatto visibile utilizzando originale, o Applicazioni ungherese Notation (H. N.). Se pensate che H. N. significhi il tipo-nome-come-prefisso, vi sbagliate (è il Sistema H. ​​N., ed è, hm, inutile nomenclatura).

Utilizzando le (App) H. N., il prefisso di variabile indica non il tipo (ad esempio int), ma lo scopo, ad es. contatore, lunghezza, secondi ecc. Quindi, quando si aggiunge un contatore a una variabile che contiene il tempo trascorso, si scrive cntSomethingCounter + secElapsedSinceLastSomething, e si può vedere che odora. Il compilatore non avvisa, ma ti colpisce.

Per saperne di più: http://www.joelonsoftware.com/articles/Wrong.html

Problemi correlati