5

「T&&」パラメータを使用して関数テンプレートをオーバーロードすることは一般的に悪い考えです。これは何にでもバインドできるためですが、とにかくそれを行うと仮定しましょう。

template<typename T>
void func(const T& param)
{
  std::cout << "const T&\n";
}

template<typename T>
void func(T&& param)
{
  std::cout << "T&&\n";
}

私の理解では、const T&オーバーロードは定数値である引数に対して呼び出され、T&&オーバーロードは他のすべての引数タイプに対して呼び出されます。funcただし、constおよびnon-constコンテンツの配列を使用して呼び出すとどうなるかを考えてみてください。

int main()
{
  int array[5] = {};
  const int constArray[5] = {};

  func(array);             // calls T&& overload
  func(constArray);        // calls const T& overload
}

VC10、VC11、およびgcc 4.7は、示されている結果に同意します。私の質問は、2番目の呼び出しがなぜconst T&オーバーロードを呼び出すのかということです。簡単な答えはconstArray、constが含まれているということですが、それは単純すぎると思います。推定されるタイプT(選択されたテンプレートに関係なく)は「5const intsの配列」であるためparamconst T&オーバーロードのタイプは「5constintsのconst配列への参照」になります。ただし、constArrayという名前の配列自体は、constとして宣言されていません。では、なぜオーバーロードを呼び出さないので、func(constArray)「5つの定数の配列への参照」 T&&のタイプが生成されるのでしょうか。param

この質問は、c ++テンプレート関数の引数の推定と関数の解決での質問に関連する議論によって動機付けられていますが、スレッドは他の問題で脇道に追いやられ、私が今ここで尋ねている質問を明確にしなかったと思います。

4

2 に答える 2

7

関数パラメーターリスト(およびその他のすべての場所)では、配列型のcv修飾は、配列要素型を修飾するために正しくシャッフルされます。たとえば、を使用するとT = int [5]const T &はに変換されint const (&) [5]ます。

3.9.3CV修飾子[basic.type.qualifier]

2-[...]配列型に適用されるcv修飾子は、配列型(8.3.4)ではなく、配列要素型に影響します。

したがって、func型の引数を使用したtoint const [5]の呼び出しは、次のいずれかの呼び出しとして推定されます。

void func<int [5]>(int const (&) [5])
void func<int const (&) [5]>(int const (& &&) [5])
// where the above collapses to
// 'void func<int const (&) [5]>(int const (&) [5])'

両方のオーバーロードが実行可能ですが、前者が推奨されます。

T1をconst T &テンプレート、T2をテンプレートとしT &&ます。つまり、それらのパラメータタイプはT1:=const T &およびT2:=T &&です。次に、変換された引数の型(14.5.6.2:3)は、合成された型の場合、 A1:= const C &、A2:=と書くことができます。D &&CD

ここで、T2(14.8.2.4:2)に対してT1を注文しようとします。最初に、引数テンプレートとしてA1を使用し、パラメーターテンプレートとしてP2を使用します。const CA1->およびT2->を与える参照(14.8.2.4:5)を削除してから、A1->およびTT2->を与えるcv-qualification(14.8.2.4:7)を削除します。テンプレートは(14.8.2.4:8)と推定できるため、 A1は少なくともP2と同じくらい特殊化されています。逆に、A2-> -> 、P1-> ->であり、と推定できるため、A2は少なくともP1と同じくらい特殊化されています。CTTCDDconst TTTD

これは通常、どちらももう一方よりも専門的ではないことを意味します。ただし、PおよびA型は参照型14.8.2.4:9が適用され、A1は左辺値参照であり、P2はそうではないため、T1はT2よりも特殊であると見なされます。(参照型間の結びつきは、同じ節のcv-qualificationによっても解除できます。)

于 2012-09-11T17:35:37.870 に答える
3

右辺値参照(のようなint&&)とユニバーサル参照(のようにテンプレートパラメーターから作成される)を混同していますtemplate <typename T> ... T&&

右辺値参照は実際には左辺値にバインドされません。しかし、普遍的な参照は何にでもバインドします。問題は、誰がより良いマッチであるかということです。

あなたが持っているタイプはですint const [5]。今見てみましょう:

  • に対してT const &:と一致しT = int[5]ます。

  • に対してT &&:と一致しT = int const (&)[5]ます。

前者は、次の意味でより適切に一致します。両方のテンプレートが同じオーバーロードを生成します。しかしT = int[5]より専門的ですT = int const (&)[5]。とT = int const (&)[5]同じように実現できるので、これを見ることができます。T = U const &U = int[5]

左辺値をユニバーサル参照にバインドするには、型自体を参照型として推定する必要があることに注意してください。

(constではないため、明らかにarray一致しませんconst T &。一致することしかできませんT&&、推論しT = int (&)[5]ます)。

于 2012-09-11T17:21:40.767 に答える