私は「テンプレート引数の控除がここで機能しないのはなぜですか?」に最近遭遇し、答えをまとめることができます「推論されていないコンテキストです」へ。
具体的には、最初の1つはそれがそのようなものであると言ってから「詳細」の標準にリダイレクトし、2番目の1つは標準を引用していますが、控えめに言っても不可解です。
非推論コンテキストとは何か、いつ発生するのか、なぜ発生するのか、誰かが私のように単なる人間に説明できますか?
控除は、与えられた引数からテンプレートパラメータのタイプを決定するプロセスを指します。関数テンプレート、auto
、およびその他のいくつかのケース(部分的な特殊化など)に適用されます。たとえば、次のことを考慮してください。
_template <typename T> void f(std::vector<T>);
_
_std::vector<int> x;
_を宣言したf(x)
と言うと、T
はdeduced as int
となり、特殊化されます。 _f<int>
_。
推論が機能するためには、推論されるテンプレートパラメータタイプが推論可能なコンテキストで表示される必要があります。この例では、f
の関数パラメーターはそのような推測可能なコンテキストです。つまり、関数呼び出し式の引数により、呼び出し式を有効にするためにテンプレートパラメーターT
を決定することができます。
ただし、非-演繹されたコンテキストもあり、演繹は不可能です。正規の例は、「_::
_の左側に表示されるテンプレートパラメータです。
_template <typename> struct Foo;
template <typename T> void g(typename Foo<T>::type);
_
この関数テンプレートでは、関数パラメーターリストのT
が非推論コンテキストにあります。したがって、g(x)
と言ってT
を推定することはできません。この理由は、任意の型とmembers _Foo<T>::type
_の間に「後方対応」がないためです。たとえば、次のような特殊化を行うことができます。
_ template <> struct Foo<int> { using type = double; };
template <> struct Foo<char> { using type = double; };
template <> struct Foo<float> { using type = bool; };
template <> struct Foo<long> { int type = 10; };
template <> struct Foo<unsigned> { };
_
g(double{})
を呼び出すと、T
には2つの可能な答えがあり、g(int{})
を呼び出すと、答えはありません。一般に、クラステンプレートパラメーターとクラスメンバーの間に関係はないため、実用的な引数の推定は実行できません。
場合によっては、引数の演繹を明示的に禁止すると便利です。これは、たとえば_std::forward
_の場合です。もう1つの例は、_Foo<U>
_から_Foo<T>
_への変換など、他の変換がある場合です(_std::string
_および_char const *
_と考えてください)。次に、無料の関数があるとします。
_template <typename T> bool binary_function(Foo<T> lhs, Foo<T> rhs);
_
binary_function(t, u)
を呼び出すと、控除が曖昧になり、失敗する場合があります。ただし、引数を1つだけ推論し、notをもう1つ推論するのが妥当なので、暗黙的な変換が可能になります。ここで、たとえば次のように、明示的に推論されていないコンテキストが必要です。
_template <typename T>
struct type_identity {
using type = T;
};
template <typename T>
bool binary_function(Foo<T> lhs, typename type_identity<Foo<T>>::type rhs)
{
return binary_function(lhs, rhs);
}
_
(あなたはstd::min(1U, 2L)
のようなものでそのような演繹問題を経験したかもしれません。)