検討する
#include <iostream>
#include <type_traits>
template <class T, class ARG_T = T&>
T foo(ARG_T v){
return std::is_reference<decltype(v)>::value;
}
int main() {
int a = 1;
std::cout << foo<int>(a) << '\n';
std::cout << foo<int, int&>(a) << '\n';
}
どちらの場合も出力は1になると思います。ただし、最初のケースでは0です。デフォルトはclass ARG_T = T
ではなくclass ARG_T = T&
です。
何が欠けていますか?
foo<int>(a)
、ARG_T
はa
から推定されており、デフォルトのテンプレート引数から取得されていません。これは値渡しの関数パラメーターであり、a
はint
型の式であるため、int
と推定されます。
一般に、デフォルトのテンプレート引数は、テンプレート引数の推定により引数が何であるかを検出できる場合は使用されません。
ただし、関数パラメーターに非推定コンテキストを導入することで、デフォルト引数の使用を強制できます。例えば:
template <class T, class ARG_T = T&>
T foo(std::enable_if_t<true, ARG_T> v1){
//...
}
またはC++ 20 type_identity
ユーティリティなど、他の回答が示しています。
関数の引数v
からARG_T
の- テンプレート引数の控除 を停止する必要があります( std::type_identity
を使用して、特定の引数を演繹から除外するために使用できます)。それ以外の場合、デフォルトのテンプレート引数は使用されません。例えば.
template <class T, class ARG_T = T&>
T foo(std::type_identity_t<ARG_T> v){
return std::is_reference<decltype(v)>::value;
}
ところで:コンパイラがstd::type_identity
をサポートしていない場合(C++ 20以降)、独自に作成する場合があります。
template<typename T> struct type_identity { typedef T type; };
template< class T >
using type_identity_t = typename type_identity<T>::type;