最終更新:2026-10-12
C++17 クラステンプレートのテンプレート引数推論 CTAD¶
導入¶
C++テンプレートメタプログラミングは、初心者から上級者まで、型パラメータを持つ汎用コードを書けることでC++開発者に広く知られた機能です。C++17でクラステンプレートのテンプレート引数推論(CTAD)が導入され、クラステンプレートを扱うプロセスはより直感的で柔軟になりました。
本節のすべてのコードもコミュニティで公開されます。
C++17でCTADが導入されたことには、次のような利点があります:
例えば、このような複雑なコードを
次のように書くだけで済みます:
別の例:
このように簡潔にできます:
というわけで、今日はCTADを見ていきましょう。
CTADはClass template argument deduction (CTAD)の略称で、クラステンプレートの引数推論のことです。コンパイラに推論ガイド(deduction guide)を与えると、この機能を使えるようになります。
与えない場合は、次の例のようになります:
#include <iostream>
template <typename T, typename U>
struct MyPair {
T first{};
U second{};
};
int main() {
MyPair<int, int> p1{1, 2};
MyPair p2{1, 2};
std::cout << p1.first << ", " << p1.second << std::endl;
std::cout << p2.first << ", " << p2.second << std::endl;
return 0;
}
p2に対しては、次のエラーが出ます:
no viable constructor or deduction guide for deduction of template arguments of 'MyPair'
では、どう直せばよいのでしょうか?
deduction guideを追加するだけで、次のように書くだけです。
クラステンプレートのテンプレート引数推論(CTAD)は、コンパイラがコンストラクタ引数からテンプレート引数を推論することを許すことで、クラステンプレートのインスタンス化プロセスを簡素化します。CTADが導入される前は、開発者はインスタンス化の際にテンプレート引数を明示的に指定しなければなりませんでした。しかしCTADによって、この明示的な指定は不要になり、コードはより読みやすく、保守しやすくなります。
template <typename T>
class Add{
private:
T first;
T second;
public:
Add() = default;
Add(T first, T second): first_{first}, second_{second} {}
T result() const { return first + second; }
};
int main(){
Add one(1,2); // T被推导为int
Add two{1.245, 3.1415}; // T被推导为double
Add three = {0.24f, 0.34f}; // T被推导为float
}
上の例では、CTADによって型Tがコンストラクタ引数に基づいて推論され、明示的な型指定の必要性がなくなります。
非静的メンバの初期化¶
しかし、CTADが使えない場面が1つあります。それは非静的メンバの初期化です。例えば、Testクラスの中で外のMyPairを使うには、すべて書き切らなければなりません。
template <typename T = int, typename U = int>
struct MyPair {
T first{};
U second{};
};
template <typename T, typename U>
MyPair(T, U) -> MyPair<T, U>;
class Test {
MyPair p4; // use of class template 'MyPair' requires template arguments; argument
// deduction not allowed in non-static class member
};
上の例では、テンプレートクラスMyPairを定義し、その中でCTADを使いました。しかし、クラスTestの中でMyPairを非静的メンバとして使おうとすると、非静的メンバ初期化という文脈のためCTADが正しく機能せず、コンパイルエラーになります。この場合、MyPairのテンプレート引数を明示的に指定しなければなりません。
非静的メンバ初期化の文脈では、CTADがテンプレート引数を推論できないことがわかります。したがって、クラステンプレートを非静的メンバとして使う場合、開発者はすべてのテンプレート引数を明示的に指定する必要があります。コードの正しさと保守性を確保するためにも、実際の開発ではこの点に特に注意してください。
関連トピック¶
- C++17 [[nodiscard]] 属性 | C++那些事
- C++17 std::string_view | C++那些事
- C++17 PMR メモリリソース | C++那些事
- C++17 17の高度な機能 | C++那些事
- C++17 optional_ref | C++那些事
- C++17 std::variant | C++那些事
- C++17 構造化束縛 | C++那些事
- C++17 テンプレート auto 推論 | C++那些事
- C++17 変数テンプレート | C++那些事