decltype
(C++)
decltype
型指定子は、指定された式の型を生成します。 decltype
型指定子は、auto
キーワードと共に使用され、主にテンプレート ライブラリを記述する開発者にとって有益です。 戻り値の型がテンプレート引数の型に依存する関数テンプレートを使用 auto
して decltype
宣言します。 または、別の関数の呼び出しをラップしdecltype
、ラップされた関数の戻り値の型を返す関数テンプレートを使用auto
して宣言します。
構文
decltype(
expression
)
パラメーター
expression
式。 詳細については、「式」をご覧ください。
戻り値
expression
パラメーターの型。
解説
decltype
型指定子は、Visual Studio 2010 以降のバージョンでサポートされ、ネイティブ コードまたはマネージド コードと共に使用できます。 decltype(auto)
(C++14) は Visual Studio 2015 以降でサポートされています。
コンパイラは、次の規則を使用してパラメーターの型を expression
決定します。
パラメーターが
expression
識別子またはクラス メンバー アクセスである場合はexpression
、decltype(expression)
. このようなエンティティがない場合、またはパラメーターにexpression
オーバーロードされた関数のセットの名前が付いている場合、コンパイラはエラー メッセージを生成します。パラメーターが
expression
関数またはオーバーロードされた演算子関数の呼び出しである場合は、decltype(expression)
関数の戻り値の型です。 オーバーロードされた演算子を囲んでいるかっこは無視されます。パラメーターが
expression
右辺値の場合、decltype(expression)
の型expression
です。 パラメーターがexpression
左辺値の場合は、decltype(expression)
次のexpression
型への左辺値参照です。
decltype
型指定子のいくつかの使用方法を次のコード例に示します。 まず、次のステートメントをコーディングしたとします。
int var;
const int&& fx();
struct A { double x; };
const A* a = new A();
次に、次の表の 4 つの decltype
ステートメントによって返される型をチェックします。
ステートメント | 型 | Notes |
---|---|---|
decltype(fx()); |
const int&& |
const int への右辺値参照。 |
decltype(var); |
int |
変数 var の型。 |
decltype(a->x); |
double |
メンバー アクセスの型。 |
decltype((a->x)); |
const double& |
内側のかっこは、ステートメントをメンバー アクセスではなく式として評価します。 そして、a は const ポインターとして宣言されているため、型は const double への参照です。 |
decltype
および auto
C++14 では、後続の戻り値の型なしで使用 decltype(auto)
して、戻り値の型がテンプレート引数の型に依存する関数テンプレートを宣言できます。
C++11 では、後続のdecltype
戻り値の型指定子をキーワード (keyword)とauto
共に使用して、戻り値の型がそのテンプレート引数の型に依存する関数テンプレートを宣言できます。 たとえば、関数テンプレートの戻り値の型がテンプレート引数の型に依存する次のコード例を考えてみましょう。 コード例では、プレースホルダーは UNKNOWN
戻り値の型を指定できないことを示しています。
template<typename T, typename U>
UNKNOWN func(T&& t, U&& u){ return t + u; };
型指定子の decltype
導入により、開発者は関数テンプレートから返される式の型を取得できます。 late-specified 戻り型を宣言するには、後述する代替関数宣言構文、auto
キーワード、および decltype
型指定子を使用します。 遅延指定の戻り値の型は、宣言がコード化されたときではなく、コンパイル時に決定されます。
次のプロトタイプは代替関数宣言の構文について説明します。 修飾子 const
と volatile
例外の throw
指定 は省略可能です。 プレースホルダーは function_body
、関数の動作を指定する複合ステートメントを表します。 ベスト コーディングの方法として、ステートメント内のexpression
decltype
プレースホルダーは、ステートメントでreturn
指定された式 (存在するfunction_body
場合) と一致する必要があります。
auto
function_name
(
parameters
opt)
const
opt opt optexpression
)
decltype(
->
noexcept
volatile
{
function_body
};
次のコード例では、関数テンプレートの遅延指定された戻り値のmyFunc
型は、引数とu
テンプレート引数のt
型によって決まります。 コーディングの推奨手順として、コード例では、右辺値の参照と完全転送をサポートする forward
関数テンプレートも使用しています。 詳細については、「右辺値参照宣言子: &>」を参照してください。
//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
関数と転送関数 (C++11)
転送関数は、他の関数の呼び出しをラップします。 関数テンプレートで、引数、またはそれらの引数を含む式の結果を別の関数に転送する場合を考えます。 さらに、転送関数は、他の関数を呼び出した結果を返します。 このシナリオでは、転送関数の戻り値の型は、ラップされた関数の戻り値の型と同じである必要があります。
このシナリオでは、型指定子なしで適切な型式を decltype
記述することはできません。 型指定子は decltype
、関数が参照型を返すかどうかに関する必要な情報を失わないので、ジェネリック転送関数を有効にします。 転送関数のコード例については、前 myFunc
の関数テンプレートの例を参照してください。
例
次のコード例では、関数テンプレート Plus()
の遅延指定された戻り値の型を宣言します。 Plus
の関数は operator+
オーバーロードを持つ 2 つのオペランドを処理します。 したがって、プラス演算子 (+
) と関数の戻り値の型の Plus
解釈は、関数引数の型によって異なります。
// 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
Visual Studio 2017 以降: コンパイラは、テンプレートがインスタンス化されるときではなく宣言されるときに、decltype
引数を解析するようになりました。 したがって、引数に decltype
非依存の特殊化が見つかった場合、インスタンス化時に遅延されることはありません。すぐに処理され、その時点で結果のエラーが診断されます。
次の例は、宣言時に発生するこのようなコンパイラ エラーを示しています。
#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");
要件
Visual Studio 2010 以降のバージョン。
decltype(auto)
には、Visual Studio 2015 以降が必要です。
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示