decltype
(C++)
Specyfikator decltype
typu zwraca typ określonego wyrażenia. Specyfikator decltype
typu wraz ze auto
słowem kluczowym jest przydatny głównie dla deweloperów, którzy piszą biblioteki szablonów. Użyj auto
funkcji i decltype
, aby zadeklarować szablon funkcji, którego typ zwracany zależy od typów argumentów szablonu. Możesz też użyć polecenia auto
i decltype
zadeklarować szablon funkcji, który opakowuje wywołanie innej funkcji, a następnie zwraca zwracany typ opakowanej funkcji.
Składnia
decltype(
expression
)
Parametry
expression
Wyrażenie. Aby uzyskać więcej informacji, zobacz Wyrażenia.
Wartość zwracana
Typ parametru expression
.
Uwagi
Specyfikator decltype
typu jest obsługiwany w programie Visual Studio 2010 lub nowszych wersjach i może być używany z kodem natywnym lub zarządzanym. decltype(auto)
(C++14) jest obsługiwany w programie Visual Studio 2015 lub nowszym.
Kompilator używa następujących reguł, aby określić typ parametru expression
.
expression
Jeśli parametr jest identyfikatorem lub dostępem do składowej klasy,decltype(expression)
jest typem jednostki o nazwie .expression
Jeśli nie ma takiej jednostki lubexpression
parametrów nazw zestaw przeciążonych funkcji, kompilator zwraca komunikat o błędzie.expression
Jeśli parametr jest wywołaniem funkcji lub przeciążonej funkcji operatora,decltype(expression)
jest zwracanym typem funkcji. Nawiasy wokół przeciążonego operatora są ignorowane.expression
Jeśli parametr jest rvalue,decltype(expression)
jest typemexpression
.expression
Jeśli parametr jest lvalue,decltype(expression)
jest odwołaniem lvalue do typuexpression
.
W poniższym przykładzie kodu pokazano niektóre zastosowania specyfikatora decltype
typu. Najpierw załóżmy, że kodowane są następujące instrukcje.
int var;
const int&& fx();
struct A { double x; };
const A* a = new A();
Następnie sprawdź typy zwracane przez cztery decltype
instrukcje w poniższej tabeli.
Oświadczenie | Type | Uwagi |
---|---|---|
decltype(fx()); |
const int&& |
Odwołanie rvalue do elementu const int . |
decltype(var); |
int |
Typ zmiennej var . |
decltype(a->x); |
double |
Typ dostępu do elementu członkowskiego. |
decltype((a->x)); |
const double& |
Nawiasy wewnętrzne powodują, że instrukcja ma być oceniana jako wyrażenie zamiast dostępu do elementu członkowskiego. A ponieważ a jest zadeklarowany jako const wskaźnik, typ jest odwołaniem do const double . |
decltype
i auto
W języku C++14 można użyć bez decltype(auto)
typu powrotu końcowego, aby zadeklarować szablon funkcji, którego typ zwracany zależy od typów argumentów szablonu.
W języku C++11 można użyć decltype
specyfikatora typu końcowego zwracanego wraz ze auto
słowem kluczowym, aby zadeklarować szablon funkcji, którego typ zwracany zależy od typów argumentów szablonu. Rozważmy na przykład następujący przykład kodu, w którym zwracany typ szablonu funkcji zależy od typów argumentów szablonu. W przykładzie kodu symbol zastępczy wskazuje, UNKNOWN
że nie można określić typu zwracanego.
template<typename T, typename U>
UNKNOWN func(T&& t, U&& u){ return t + u; };
Wprowadzenie specyfikatora decltype
typu umożliwia deweloperowi uzyskanie typu wyrażenia zwracanego przez szablon funkcji. Użyj składni deklaracji funkcji alternatywnej, która jest wyświetlana później, auto
słowo kluczowe i decltype
specyfikator typu, aby zadeklarować późno określony typ zwracany. Określony późno typ zwracany jest określany podczas kompilowania deklaracji, a nie podczas jego kodowania.
Poniższy prototyp ilustruje składnię alternatywnej deklaracji funkcji. Kwalifikatory const
i volatile
oraz specyfikacja wyjątku throw
są opcjonalne. Symbol function_body
zastępczy reprezentuje instrukcję złożoną, która określa, co robi funkcja. Najlepszym rozwiązaniem expression
w zakresie kodowania jest dopasowanie symbolu zastępczego w instrukcji decltype
do wyrażenia określonego przez instrukcję return
, jeśli istnieje, w elemecie function_body
.
auto
function_name
(
parameters
opt )
const
opt opt opt volatile
->
decltype(
expression
)
noexcept
{
function_body
};
W poniższym przykładzie kodu typ zwracany późno określony szablon myFunc
funkcji jest określany przez typy t
argumentów i u
szablonu. Najlepszym rozwiązaniem w zakresie kodowania jest również użycie odwołań rvalue i szablonu forward
funkcji, które obsługują doskonałe przekazywanie. Aby uzyskać więcej informacji, zobacz Deklarator odwołań Rvalue: &&.
//C++11
template<typename T, typename U>
auto myFunc(T&& t, U&& u) -> decltype (forward<T>(t) + forward<U>(u))
{ return forward<T>(t) + forward<U>(u); };
//C++14
template<typename T, typename U>
decltype(auto) myFunc(T&& t, U&& u)
{ return forward<T>(t) + forward<U>(u); };
decltype
funkcje przekazywania (C++11)
Funkcje przekazujące zawijają wywołania do innych funkcji. Rozważ szablon funkcji, który przekazuje swoje argumenty lub wyniki wyrażenia, które obejmuje te argumenty, do innej funkcji. Ponadto funkcja przekazywania zwraca wynik wywoływania innej funkcji. W tym scenariuszu zwracany typ funkcji przekazywania powinien być taki sam jak zwracany typ opakowanej funkcji.
W tym scenariuszu nie można napisać odpowiedniego wyrażenia typu bez specyfikatora decltype
typu. Specyfikator decltype
typu włącza ogólne funkcje przekazywania, ponieważ nie traci wymaganych informacji o tym, czy funkcja zwraca typ odwołania. Przykładowy kod funkcji przekazywania można znaleźć w przykładzie poprzedniego myFunc
szablonu funkcji.
Przykłady
Poniższy przykład kodu deklaruje późno określony typ zwracany szablonu Plus()
funkcji . Funkcja Plus
przetwarza dwa operandy z operator+
przeciążeniem. Dlatego interpretacja operatora plus (+
) i zwracanego typu Plus
funkcji zależy od typów argumentów funkcji.
// decltype_1.cpp
// compile with: cl /EHsc decltype_1.cpp
#include <iostream>
#include <string>
#include <utility>
#include <iomanip>
using namespace std;
template<typename T1, typename T2>
auto Plus(T1&& t1, T2&& t2) ->
decltype(forward<T1>(t1) + forward<T2>(t2))
{
return forward<T1>(t1) + forward<T2>(t2);
}
class X
{
friend X operator+(const X& x1, const X& x2)
{
return X(x1.m_data + x2.m_data);
}
public:
X(int data) : m_data(data) {}
int Dump() const { return m_data;}
private:
int m_data;
};
int main()
{
// Integer
int i = 4;
cout <<
"Plus(i, 9) = " <<
Plus(i, 9) << endl;
// Floating point
float dx = 4.0;
float dy = 9.5;
cout <<
setprecision(3) <<
"Plus(dx, dy) = " <<
Plus(dx, dy) << endl;
// String
string hello = "Hello, ";
string world = "world!";
cout << Plus(hello, world) << endl;
// Custom type
X x1(20);
X x2(22);
X x3 = Plus(x1, x2);
cout <<
"x3.Dump() = " <<
x3.Dump() << endl;
}
Plus(i, 9) = 13
Plus(dx, dy) = 13.5
Hello, world!
x3.Dump() = 42
Program Visual Studio 2017 lub nowszy: kompilator analizuje decltype
argumenty, gdy szablony są deklarowane, a nie tworzone wystąpienia. Tak więc, jeśli specjalizacja nie zależna zostanie znaleziona w argumencie decltype
, nie zostanie odroczona do czasu utworzenia wystąpienia; jest ona przetwarzana natychmiast i wszelkie błędy wynikowe są diagnozowane w tym czasie.
W poniższym przykładzie pokazano taki błąd kompilatora, który jest zgłaszany w momencie deklaracji:
#include <utility>
template <class T, class ReturnT, class... ArgsT> class IsCallable
{
public:
struct BadType {};
template <class U>
static decltype(std::declval<T>()(std::declval<ArgsT>()...)) Test(int); //C2064. Should be declval<U>
template <class U>
static BadType Test(...);
static constexpr bool value = std::is_convertible<decltype(Test<T>(0)), ReturnT>::value;
};
constexpr bool test1 = IsCallable<int(), int>::value;
static_assert(test1, "PASS1");
constexpr bool test2 = !IsCallable<int*, int>::value;
static_assert(test2, "PASS2");
Wymagania
Visual Studio 2010 lub nowsze wersje.
decltype(auto)
program wymaga programu Visual Studio 2015 lub nowszego.