Najlepsze pytania
Chronologia
Czat
Perspektywa
Decltype
Z Wikipedii, wolnej encyklopedii
Remove ads
decltype – operator pozwalający na uzyskanie typu wyrażenia w języku programowania C++. Został on wprowadzony w wersji C++11 standardu C++. Jego głównym przeznaczeniem jest programowanie uogólnione, w którym często trudno, jeśli w ogóle jest to możliwe, określić typy zależne od parametrów szablonu.
Wzrost popularności technik programowania uogólnionego następował od lat dziewięćdziesiątych XX wieku. Wówczas zauważona została potrzeba mechanizmu do wyznaczania typu. Wielu producentów kompilatorów wdrożyło własne wersje takiego operatora, zazwyczaj nazywanego typeof
oraz opracowało pewne przenośne implementacje o ograniczonej funkcjonalności, na bazie istniejących funkcji języka. W 2002 roku Bjarne Stroustrup zaproponował, aby standardową formę takiego operatora dodać do języka C++ i zasugerował nazwę „decltype”, aby odzwierciedlić, że operator zwraca „deklarowany typ” wyrażenia.
Semantyka decltype
została tak zaprojektowana, aby zaspokoić potrzeby autorów bibliotek z kodem uogólnionym, jak również początkujących programistów. W ogólności, typ określony za pomocą tego operatora zgadza się z typem obiektu lub funkcji zadeklarowanym w kodzie źródłowym. Podobnie jak w przypadku operatora sizeof
, operand decltype
nie jest wykonywany.
Remove ads
Motywacja
Podsumowanie
Perspektywa
Po wprowadzeniu szablonów w języku programowania C++ i tym samym umożliwieniu programowania uogólnionego, zapoczątkowanego przez standardową bibliotekę szablonów, zauważono potrzebę mechanizmu uzyskiwania typu wyrażenia, powszechnie określanego mianem typeof
. W programowaniu uogólnionym często trudno określić typ zależny od parametrów szablonu lub jest to niemożliwe[1][2], zwłaszcza gdy chodzi o typ wyniku funkcji realizowanej w definicji szablonu[1].
Wielu producentów dostarcza operator typeof
jako rozszerzenie kompilatora[3]. Już w 1997 roku, zanim C++ został w pełni ustandaryzowany, Brian Parker zaproponował przenośne rozwiązanie wykorzystujące operator sizeof
[3]. Następnie pracę tę poszerzył Bill Gibbons, który stwierdził, że ta technika ma kilka ograniczeń i w ogólności jest mniej skuteczna niż rzeczywisty mechanizm typeof
[3]. W październiku 2000 roku w artykule w Dr. Dobb's Journal, Andrei Alexandrescu zauważył że, posiadanie operatora typeof
znacznie by uprościło pisanie i rozumienie szablonów[4]. Wspomniał również, że typeof
i sizeof
używają takiego samego wsparcia wewnętrznego, ponieważ operator sizeof
i tak musi najpierw określić typ[4]. Andrew Koenig i Barbara E. Moo także dostrzegli przydatność wbudowanego ułatwienia typeof
, z zastrzeżeniem, że częste jego użycie może powodować pewne subtelne błędy, oraz że istnieją pewne problemy, których on nie rozwiązuje[5]. Scharakteryzowali użycie konwencji typu, jak typedef dostarczany przez standardową bibliotekę szablonów jako technikę bardziej skuteczną i ogólną[5]. Jednak Steve Dewhurst argumentował, że takie konwencje są kosztowne do zaprojektowania i ogłoszenia, a także byłoby o wiele łatwiej po prostu wyodrębnić typ wyrażenia[6]. W artykule z 2011 roku na temat C++0x, Koenig i Moo przewidzieli, że decltype
będzie szeroko stosowany, aby codzienne programowanie było łatwiejsze w pisaniu[7].
W 2002 roku Bjarne Stroustrup zasugerował rozszerzenie języka C++ o mechanizm pozwalający uzyskać typ z wyrażenia i zainicjować obiekt bez określania typu[1]. Stroustrup zaobserwował, że problemem może być semantyka odrzucania referencji oferowana przez operator typeof
zapewniana przez kompilatory GCC i EDG[1]. Z drugiej strony, operator zwracający typ referencyjny oparty na l-wartościowości wyrażenia został uznany za zbyt skomplikowany. Początkowy wniosek do komisji standaryzacji C++ nakreślił kombinację dwóch wariantów; operator zwracałby typ referencyjny tylko jeśli zadeklarowany typ wyrażenia zawierałby referencję. Aby podkreślić, że dedukowany typ pochodzi od „deklarowanego typu” wyrażenia, nazwa zaproponowanego operatora to decltype
[1].
Jednym z najczęściej cytowanych motywów wprowadzenia proponowanego operatora decltype
była możliwość zapisu w szablonach idealnych funkcji przekierowujących[8]. Jest czasami pożądane, aby utworzyć uogólnioną funkcję przekierowującą, która zwraca taki sam typ wyniku jak funkcja docelowa bez względu na rodzaj jego tworzenia. Bez decltype
, nie jest to w ogólności możliwe[8]. Przykład stosujący również nową składnie deklaracji i definicji funkcji[8]:
int& foo(int& i);
float foo(float& f);
template <class T> auto transparent_forwarder(T& t) −> decltype(foo(t)) {
return foo(t);
}
Istotą operatora decltype
w powyższym przykładzie jest zachowanie informacji o tym czy docelowa funkcja zwraca typ referencyjny[9].
Remove ads
Semantyka
Podsumowanie
Perspektywa
Podobnie jak w operatorze sizeof
, operand decltype
nie jest wykonywany[10]. Nieformalnie, typ zwracany przez decltype
jest wydedukowany następująco[1]:
- jeśli wyrażenie
e
odwołuje się do zmiennej w zakresie lokalnym lub w przestrzeni nazw, statycznej zmiennej klasy lub parametru funkcji, to wynikiem jest zadeklarowany typ zmiennej lub parametru - jeśli
e
jest wywołaniem funkcji lub użyciem przeciążonego operatora,decltype(e)
oznacza zadeklarowany typ wyniku tej funkcji - w przeciwnym razie, jeśli
e
to l-wartość,decltype(e)
toT&
, gdzieT
jest typeme
; jeślie
jest r-wartością, to wynikiem jestT
.
Semantyka została tak zaprojektowana, aby spełnić oczekiwania autorów bibliotek z kodem uogólnionym, a ponadto jest intuicyjna dla początkujących programistów, ponieważ zwracany typ przez decltype
zawsze dokładnie zgadza się z typem obiektu lub funkcji zadeklarowanym w kodzie źródłowym[1]. Bardziej formalnie, reguła #1 ma zastosowanie do beznawiasowych id-expression[a] i wyrażeń dostępu do składowych klasy[12]. Dla wywołań funkcji wydedukowany typ to typ zwracany przez statycznie wybraną funkcję, określoną według reguł przeciążania funkcji[13]. Przykład[12]:
const int&& foo();
int i;
struct A { double x; };
const A* a = new A();
decltype(foo()) x1; // typ to const int&&
decltype(i) x2; // typ to int
decltype(a->x) x3; // typ to double
decltype((a->x)) x4; // typ to const double&
Powodem różnic w ostatnich dwóch wywołaniach decltype
jest to, że wyrażenie w nawiasie (a->x)
nie jest ani id-expression ani dostępem do skladowych klasy, a stąd nie oznacza nazwanego obiektu[14]. Ponieważ to wyrażenie jest l-wartością, jego wydedukowany typ jest referencją do typu wyrażenia, czyli const double&
[10].
W grudniu 2008 Jaakko Järvi zgłosił problem do komisji, że decltype
nie można zastosować do utworzenia qualified-id[15][b], co jest niespójne z intencją, że decltype
powinien być traktowany tak jakby był typedef-name[16][c]. W odniesieniu do Committee Draft for C++0x, członek japońskiej ISO zauważył, że operator zakresu (::) nie może być zastosowany do decltype, a powinien. Byłoby to pożyteczne, żeby uzyskać typ bazowy w typie pochodnym z wystąpienia obiektu jak w przykładzie[18]:
vector<int> v;
decltype(v)::value_type i = 0; // int i = 0;
Te i podobne kwestie odnoszące się do treści wstrzymującej stosowalność decltype
w deklaracji klasy potomnej i w wywołaniu destruktora, zostały zaadresowane i zagłosowane przez Davida Vandevoorde'a w dokumencie roboczym z marca 2010[19][20].
Remove ads
Dostępność
decltype
jest zawarty w obecnej wersji standardu języka C++, C++11[12]. Jest zapewniany przez wiele kompilatorów jako rozszerzenie. Kompilator Microsoft Visual C++ 2010 dostarcza operator decltype
, który dość wiernie naśladuje specyfikację opisaną we wniosku do komitetu standaryzującego. Może on być stosowany zarówno w kodzie zarządzanym jak i natywnym[9]. Dokumentacja stanowi, że jest „użyteczny głównie dla programistów, którzy piszą biblioteki szablonów”[9]. decltype
został dodany do głównej linii kompilatorów C++ GCC w wersji 4.3[21], wydanych 5 marca 2008[22]. Operator ten jest również obecny w C++ Builder 2009[23] od CodeGear i Clang[24].
Uwagi
Przypisy
Linki zewnętrzne
Wikiwand - on
Seamless Wikipedia browsing. On steroids.
Remove ads