2012-06-21 6 views
6

Mam kod Java, gdzie typ zwracany funkcji ma nieograniczony typ wieloznaczny (?). Jak mogę emulować coś takiego w C++? na przykładJak naśladować generics typu "znak zapytania (?)" W języku Java do C++?

public GroupHandlerSetting<?> handleGroupProcessingFor(final EventHandler<T> eventHandler) 
    { 
     return new GroupHandlerSetting<T>(eventHandler, eventProcessors); 
    } 
+4

A szablony C++ nie są nawet trochę podobne do Java Generics. Szablony C++ tworzą nowe typy; Java Generics ogranicza istniejące typy. Szablony C++ to w zasadzie preproces z niektórymi zaimplementowanymi regułami; Java Generics jest zbudowany na teorii typów. Nie daj się uwieść stwierdzeniu, że są blisko odpowiednikami. Nie są. – EJP

+3

Joshua Bloch stwierdza w różnych filmach, że nie należy używać symboli wieloznacznych w przypadku typów zwrotu. Czy jesteś pewien, że są dobrym pomysłem w twoim przypadku? Czy możesz opublikować funkcję lub przynajmniej jej podpis? – fredoverflow

+0

proszę, czy mógłbyś dodać funkcję? –

Odpowiedz

6

W C++ wszystkie argumenty typu musi mieć nazwę, czy go używać, czy nie, więc nie ma znaku zapytania. Po prostu ustaw jako argument szablonu funkcję i nadaj jej nazwę, a powinieneś mieć się dobrze.

template <typename T> 
struct templ { 
    template <typename U> 
    void assign(templ<U> & u);  // public void assign<?>(temple<U> u)  
}; 

To trywialne część, tym bardziej skomplikowana część jest egzekwowanie ograniczeń dotyczących rodzaju, a do tego można użyć SFINAE:

template <typename T> 
struct templ { 
    template <typename U, typename _ = std::enable_if< 
           typename std::is_base_of<U,T>::value 
             >::type > 
    void super(templ<U> & u);  // public void super_<? super T>(templ<?> u) 

    template <typename U, typename _ = std::enable_if< 
           typename std::is_base_of<T,U>::value 
             >::type > 
    void extends(templ<U> & u);  // public void extends_<? extends T>(templ<?> u) 
} 

To jest za pomocą C++ 11 do SFINAE, w C++ 03, jest nieco bardziej skomplikowany (jak gdyby ta wersja była prosta), ponieważ nie można używać SFINAE w argumencie szablonu funkcji, więc SFINAE musi być zastosowana do argumentów typu powrotu lub funkcji dodatkowej. SFINAE jest znacznie potężniejszym rozwiązaniem, może być używane nie tylko do zapewnienia super i extends, ale także wielu innych funkcji typów lub wartości czasu kompilacji. Google dla SFINAE, a znajdziesz wiele przypadków użycia SFINAE, wiele z nich będzie w stylu C++ 03.

Pojawiła się propozycja dla koncepcji, które znacznie uprościłyby składnię, ale nie osiągnięto porozumienia i w ruchu, aby przesunąć standard do końca, został on odłożony na późniejszy standard.

To naprawdę nie jest tak powszechne w C++, jak to jest w Javie, więc zalecam, aby podać inne pytanie z tym, co chcesz zrobić, a otrzymasz pomysły na projekty w bardziej idiomatycznym C++.

+2

To nie jest dokładnie to samo. Porównaj te dwa na stronie wywołania: http://ideone.com/2LXUp i http://ideone.com/bMMJr. Jeśli chcesz emulować symbol wieloznaczny, potrzebujesz typu wymazania. –

+0

@ R.MartinhoFernandes: Szablony i generics to nie to samo, ale można zaimplementować cały ogólny kod, który można wykonać za pomocą generycznych przy użyciu szablonów. Jak na twój przykład, C++ nie obsługuje tego szczególnego * zapachu kodu *, zauważ, że eksperci w Javie nie zalecają używania '?' W instrukcjach zwrotnych, powodem jest to, że implementacja metody * zna * typ, więc nie ma powód, by tego nie publikować. Jedyną zaletą, jaką daje '?' W typie zwracanym, jest to, że nie trzeba rekompilować wywoływaczy, jeśli wywoływacz zwraca inny typ dla elementu zastępczego ... –

+0

... ale to jest faktycznie bezużyteczne w C++, jako szablonów * musi zostać zrekompilowany *, więc kompatybilność binarna (i możliwość używania kalekiego typu w witrynie wywoławczej - czyli typ, który znasz kilka małych funkcji, ale który jest dla ciebie nieznany) nie jest funkcją. W twoim przykładzie, w wersji Java zawsze zwracasz 'ArrayList ', więc równoważny przykład w C++ byłby zwykłą nietypową funkcją: 'std :: vector getSomeList()'. W pytaniu metoda jest częścią klasy generycznej (zgadywania z 'T'), a więc nie-szablonowej funkcji składowej szablonu. –

1

Twój konkretny przykład jest łatwy do wykonania, a ponieważ nie używam języka Java, nie rozumiem, dlaczego jest on potrzebny. W C++, wystarczy wypełnić tego samego parametru szablonu:

template<class T> 
GroupHandlerSetting<T> handleGroupProcessingFor(EventHandler<T> const& evHandler){ 
    return GroupHandlerSetting<T>(evHandler, evProcessors); 
} 

T dostanie wywnioskować cokolwiek argument przekazany do handleGroupProcessingFor i używamy tylko samą T dla zwracanego typu, w zasadzie dokładnie to, co robisz w Ciało funkcji.

+0

Nie jestem tego pewien. Jeśli mógłbym po prostu zastąpić z , to myślę, że jest to możliwe również w Javie. Nie wiem, dlaczego jest potrzebna . Mam małą wiedzę na temat Javy, więc mogę się mylić. – polapts

+1

@polapts: Czytanie komentarza na temat odpowiedzi Davida brzmi: "" jest potrzebne do usunięcia typu. W twoim konkretnym przykładzie możesz uciec prostą dedukcją argumentów. – Xeo

+0

@Xeo: '?' Jest typem zastępczym, w zasadzie innym argumentem typu, którego nawet nie chcesz nazwać. Możesz umieścić pewne ograniczenia na typie * nieznanym *, a mianowicie możesz wymagać, aby był on podstawą lub pochodził z innego typu (zarówno ogólnego, jak i stałego). Różnica między twoim kodem a kodem pytania polega na tym, że w twoim kodzie typ 'T' jest taki sam zarówno w argumencie, jak i w instrukcji return, podczas gdy w kodzie pytania nie jest (wewnętrznie możesz zwrócić' GroupHandlerSetting 'niezależnie od' T' i byłoby skompilować.Jest to jednak zły projekt. –