web-dev-qa-db-ja.com

演繹されないコンテキストとは何ですか?

私は「テンプレート引数の控除がここで機能しないのはなぜですか?」に最近遭遇し、答えをまとめることができます「推論されていないコンテキストです」へ。

具体的には、最初の1つはそれがそのようなものであると言ってから「詳細」の標準にリダイレクトし、2番目の1つは標準を引用していますが、控えめに言っても不可解です。

非推論コンテキストとは何か、いつ発生するのか、なぜ発生するのか、誰かが私のように単なる人間に説明できますか?

62
Shoe

控除は、与えられた引数からテンプレートパラメータのタイプを決定するプロセスを指します。関数テンプレート、auto、およびその他のいくつかのケース(部分的な特殊化など)に適用されます。たとえば、次のことを考慮してください。

_template <typename T> void f(std::vector<T>);
_

_std::vector<int> x;_を宣言したf(x)と言うと、Tdeduced 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)のようなものでそのような演繹問題を経験したかもしれません。)

84
Kerrek SB