9

パラメータパックから展開された引数で配列からポインタへの減衰を防ぐことは可能ですか?

例えば:

#include <iostream>

void foo() {
  std::cout << "empty\n";
}

template <typename T, typename... Rest>
void foo(T &&t, Rest... rest) {
  std::cout << "T, ...\n";
  foo(rest...);
}

template <typename... Rest>
void foo(char *p, Rest... rest) {
  std::cout << "char*, ...\n";
  foo(rest...);
}

template <int N, typename... Rest>
void foo(char (&first)[N], Rest... rest) {
  std::cout << "char[], ...\n";
  foo(rest...);
}

int main() {
  char a[2], b[2], c[2];
  foo(a, b, c);
}

...出力:

char[], ...
char*, ...
char*, ...
empty

ご覧のとおり、最初の呼び出しは配列ベースのオーバーロードに行きますが、その後の呼び出しはポインターベースのオーバーロードに行きます。 すべての呼び出しを配列ベースのオーバーロードに移動する方法はありますか?

関連:変数テンプレート関数の特殊化の問題

4

2 に答える 2

8

パラメータ パックを右辺値参照で渡したい場合:

void foo(char (&first)[N], Rest&&... rest)
                               ^^

したがって、コードは全体的に次のようになります。

#include <iostream>

void foo() {
  std::cout << "empty\n";
}

template <typename T, typename... Rest>
void foo(T &&t, Rest... rest) {
  std::cout << "T, ...\n";
  foo(rest...);
}

template <typename... Rest>
void foo(char *p, Rest... rest) {
  std::cout << "char*, ...\n";
  foo(rest...);
}

template <int N, typename... Rest>
void foo(char (&first)[N], Rest&&... rest) {
  std::cout << "char[], ...\n";
  foo(rest...);
}

int main() {
  char a[2], b[2], c[2];
  foo(a, b, c);
}

結果を与える:

char[], ...
char[], ...
char[], ...
empty

他のオーバーロードを同じように変更していませんが、通常は右辺値参照も使用する必要があります (実際に使用されている場合)。

編集:これを行う理由/機能する理由について:右辺値参照は、右辺値または左辺値のいずれかにバインドできます。ここで重要な点は、左辺値にバインドすると、左辺値のままであるということです。配列の場合、配列としての ID を保持するため、受け取るのは配列です。

配列を値で渡す場合、通常の関数と同じように、ポインターへの通常の「減衰」が行われます。

この特定のケースでは、通常の左辺値参照を使用することもできますが、使用した場合、左辺値ではない型では機能しませんたとえば、 を呼び出そうとすると、左辺値参照が、またはfoo(1,2,3);にバインドできないため、エラーが発生します。これに対処するために、左辺値参照を渡すことができますが、その場合、参照を右辺値に直接バインドしません。渡された右辺値のコピーを含む一時を作成し、左辺値参照をバインドします。代わりにその一時コピーに。int の特定のケースでは、それはおそらく大きな問題にはなりませんが、コピーするのによりコストがかかるもの (または、コピーではなくオリジナルにアクセスしたい場合) では、問題になる可能性があります。123const

于 2012-12-17T21:13:14.917 に答える
5

@JerryCoffinの答えはすでにその場に出ていますが、ちょっとしたコメントを付け加えたいと思いました。次のように、リスト処理コードをアイテムから分離できます。

void foo_list() {
   std::cout << "empty\n";
}

template <typename T, typename... Rest>
void foo_list(T &&t, Rest&&... rest) {
  foo(t);
  foo_list(rest...);
}

template <int N>
void foo(char (&t)[N]){
   // ...
}

void foo(char *){
   // ...
}

// etc...

(たぶん、そのためのイディオムはすでにありますか?)

于 2012-12-17T21:39:13.640 に答える