2012-09-27 10 views
7

W języku C# można napisać coś takiego:Jak uzyskać wartość domyślną każdego rodzaju

class AnyThing<T> 
    { 
     static public T Default = default(T); 
    } 

    static void Main() 
    { 
     int i = AnyThing<int>.Default; 
     Console.WriteLine (i==0); 
     string s = AnyThing<string>.Default; 
     Console.WriteLine (s == null); 

    } 

zamierzam napisać słownika jak klasy szablonu w C++, chciałbym dict aby przywrócić domyślne wartość (zero na wyjściu) ogólnego rodzaju TVal, jeśli dany klucz nie zostanie znaleziony. W C# domyślny (T) konstrukt przychodzi na ratunek, podczas gdy w C++ nie jestem pewien, jaki jest właściwy sposób robienia tego samego.

Próbowałem już T obj = {} i T* obj = {} z gcc4.7, to działa dobrze. Po prostu nie jestem pewien, czy jest to składnia zdefiniowana przez specyfikację języka, jeśli ten rodzaj kodu będzie przenośnym cross kompilatorem i platformą. Proszę, pomóż mi z moim doudtem! Z góry dziękuję!

PS:

~~~~~~~~~~

Aby upewnić się, że szablon dostać domyślne (zero out) wartość dowolnego typu, nawet tych, które nie posiadają wymagalne domyślny konstruktor, I zatrudniony następujące mechanizm (inspirowany odpowiedź avakar'S):

template<class T> 
struct AnyThing 
{ 
    static const T& Default ; 
private: 
    static const char temp[sizeof(T)]; 
}; 

template<class T> const char AnyThing<T>::temp[] = {}; 
template<class T> const T& AnyThing<T>::Default = *(T*)temp; 

struct st 
{ 
    double data; 
    st()=delete; 
}; 

int main() 
{ 
    cout << (int)AnyThing<char*>::Default<<endl; //0 
    cout << AnyThing<int>::Default<<endl;  //0 
    cout <<AnyThing<st>::Default.data<<endl;  //0 
} 

to wygląda brzydko, ale nie powinny powodować żadnych problemów, po wszystkim wyzerowany obiekt jest po prostu kawałek pustej pamięci. Czy się mylę?

+0

http://stackoverflow.com/questions/1962600/co-jest-c-cli-odpowiednik-cs-defaultt – Khurshid

+0

Nie jestem całkowicie pewien, czy to rozwiązuje twój problem, ale myślę, że [Boo st.Value Initialized] (http://www.boost.org/doc/libs/release/libs/utility/value_init.htm) próbuje rozwiązać ten problem. –

Odpowiedz

19

W języku C++ nie ma czegoś takiego jak słowo kluczowe default w języku C#. Ponieważ inicjalizacja domyślnie konstruktora wartości typu klasy nie powiedzie się, jeśli domyślnym konstruktorem jest private. W języku C#, jeśli domyślny konstruktor jest prywatny, wartość typu klasy zostanie zainicjowana na null, ponieważ typem klasy jest reference-type.

Inicjowanie przez {} jest zdefiniowane w specyfikacji językowej. To jest C++ 11. W C++ 03 należy użyć

T obj = T(); 

Jak wskazano przez bames53 w komentarzu, gdy chcesz zainicjować T* należy użyć

przed C++ 11.

T* obj = 0; 

lub

T* obj = NULL; 

C++ 11.

T* obj = {}; 

lub

T* obj = nullptr; 
+0

Czy to też działa dla typów wskaźników? – Need4Steed

+4

'double * obj = double()' nie działa. –

+1

@ Need4Steed, działa dla typów wskaźników, jeśli przez "działa" masz na myśli domyślną wartość wskaźnika o wartości null. "Works" to krótki sposób powiedzenia "spełnia moje oczekiwania"; podobnie jak dłuższa fraza, nie ujawnia, jaki właściwie jest oczekiwany wynik. Ale przynajmniej jest krótka, – rici

3

Zrobione literaly z "C++ Programming Language, Third Edition Bjarne Stroustrup":

BEGIN CYTAT

4.9.5 Inicjowanie [dcl.init]

Jeśli określono inicjator dla obiektu, inicjator ten określa wartość początkowa obiektu. Jeśli nie określono żadnego inicjalizatora, globalna (§ 4.9.4), przestrzeń nazw (§8.2) lub lokalny obiekt statyczny (§7.1.2, §10.2.4) (zwane łącznie obiektami statycznymi) jest inicjalizowany na 0 odpowiedniego typu .Na przykład:

int a; // means int a=0; 
double d; // meands d=0; 

zmienne lokalne (czasami nazywane automatyczne obiekty) i obiektów utworzonych na stercie (czasami nazywane dynamicznych obiektów lub obiektów sterty) nie są inicjowane przez domyślnie. Na przykład:

void f() 
{ 
    int x; // x does not have a well-defined value 
    // . . . 
} 

Elementy tablic i struktur są domyślnie inicjowane lub nie w zależności od tego, czy tablica lub struktura są statyczne. Zdefiniowane przez użytkownika typy mogą mieć zdefiniowaną domyślną inicjalizację (§10.4.2).

Bardziej skomplikowane obiekty wymagają więcej niż jednej wartości jako inicjatora. Jest to obsługiwane przez listy inicjalizacyjne rozdzielone przez {i} w celu inicjalizacji tablic w stylu C (§5.2.1) i struktur (§5.7).

Dla typów zdefiniowanych przez użytkownika z konstruktorami używane są listy argumentów stylu (§2.5.2, §10.2.3). Zauważ, że pusta para nawiasów() w deklaracji zawsze oznacza "funkcję" (§7.1). Na przykład:

int a[] = {1,2}; // array initializer 
Point z(1,2);  // function-style initializer (initialization by constructor) 
int f();   // function declaration 

Koniec cytatu

Tak, można uzyskać wartość domyślna dowolnego typu tworzą statyczny obiekt tego typu:

static T defaultT; // `defaultT' has de default value of type T 
+0

Ale właśnie dowiedziałem się, że rozwiązanie 'T()' przestaje działać, jeśli usunąłem moduł ochrony przed T lub zadeklarowałem go jako prywatny, ale w C# 'default (T)' działa tak czy inaczej, więc nie działa dosłownie dla dowolnego typu! Co za setback1 – Need4Steed

+2

@ Need4Steed Tak, ponieważ C# ma typy odniesienia i typy wartości. Wszystkie typy klas są typami referencyjnymi i mogą być inicjowane przez wartość null, C++ nie ma czegoś takiego. – ForEveR

+2

Najlepsza odpowiedź, bezpośrednio od twórcy C++. Dlaczego do cholery robi tę odpowiedź tak mało głosów? O wstyd! Dzięki, rany. –

3

Forever odpowiedź nie będzie działać, jeśli T robi nie ma konstruktora kopii. W C++ 03 nie ma sposobu na zerową inicjalizację zmiennej, która jest zarówno ogólna, jak i elegancka. Pozostaje tylko następująca sztuczka.

T temp[1] = {}; 
T & obj = temp[0]; 

Tutaj temp[0] wynosi zero inicjowany i związany obj. Nie są potrzebne konstruktory kopii.

1

Stwórz własną domyślną kluczowe:

class default_t 
{ 
public: 
    template<typename T> 
    operator T() const { return T(); } 
}; 

default_t const default = default_t(); 

używać go jak:

int myInt = default; 
vector<string> myVector = default; 
shared_ptr<string> myPtr = default; 

lub z nieznaczną zmianę semantyczną:

default_t const empty = default_t(); 

vector<Persons> fetchPersons() 
{ 
    if (Database::isConnected()) 
    { 
    return Database::fetchPersons(); 
    } 

    return empty; 
} 
Powiązane problemy