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 lub expression 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 typem expression. expression Jeśli parametr jest lvalue, decltype(expression) jest odwołaniem lvalue do typu expression.

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 throwsą 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.

autofunction_name(parametersopt)constopt opt optvolatile->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.