0

この残念ながら長い例は、私が書こうとしている実際のコードの簡略版です。これには 2 つの問題があります。まず、書かれているように、コンパイルされません: エラーは

error: cannot bind ‘std::string’ lvalue to ‘std::string&&’
error:   initializing argument 3 of ‘void pack_arg(datum*, size_t, std::string&&)’

への呼び出しの存在によってトリガーされshut_the_doorます。&&の関連するオーバーロードでを取り出すと、pack_argコンパイルされますが、生成されたコードは両方の文字列を不必要にコピーしているように見えます。d2 番目に、配列がポインターを保持しているすべての文字列テンポラリが、vprocess. 現在、生成されたコードは、その呼び出しの直前にそれらを破壊しているように見えます。

process他のすべてのそのような引数とは関係なく、オーバーロード可能な関数呼び出しを介して各引数を実行する機会がある限り、配列がどのように埋められるかについて非常に根本的な変更を検討するつもりです。(特に、一時的に参照を初期化するための特別な規則により、共用体で使用できれば問題 2 が解消されるのではないかと思いますstd::string&が、配列の各メンバーはdatum初期化ではなく代入によって埋められるため、現在はそうではありませんの呼び出しを失うことなく、初期化によってそれを埋める方法がわかりませんpack_arg。これは、より大きなコンテキストで必要です。)

編集:std::forward betweenpack_argsとの使用はpack_arg役に立たないようです。まったく同じエラー メッセージが表示されます。

#include <string>
#include <stddef.h>
using std::string;

union datum
{
  const string* s;
  int i;
};

inline void
pack_arg(datum* d, size_t n, int t)
{
  d[n].i = t;
}

inline void
pack_arg(datum* d, size_t n, string && t)
{
  d[n].s = &t;
}

inline void
pack_args(datum*, size_t)
{
}

template <typename X, typename... XS> inline void
pack_args(datum* d, ::size_t n, X&& x, XS&&... xs)
{
  pack_arg(d, n, x);
  pack_args(d, n+1, xs...);
}

extern void vprocess(datum*, size_t);

template <typename... XS> inline void
process(XS&&... xs)
{
  size_t n = sizeof...(xs);
  datum d[n];
  pack_args(d, 0, xs...);
  vprocess(d, n);
}

extern string shut_the_door();

void
demo()
{
  process(1, 2, "buckle my shoe", 3, 4, shut_the_door());
}
4

1 に答える 1

0

Luc は非常に興味深いポイントをもたらします (署名だけを読み取るコードを簡単に調べました)。

へのポインターをコンテナーに格納する場合は、引数が右辺値でないstd::stringことをコードで確認する必要があります。これは、関数呼び出しの完了後にダングリング ポインターが残るためです。

あなたのコードについて考えれば考えるほど、すべてが悪い考えだと思います。各要素が何であるかに関するタグがないと、配列のどの要素がどのタイプであるかを後で知ることができません。オブジェクトの寿命を維持するのは難しいでしょう (std::string特に s の場合...) 設計を完全に再考する必要があるかもしれません。


新しい C++11 構文の興味深い癖に出くわしました。これら 2 つの宣言の二重アンパサンド ( &&) は、実際には同じ意味ではありません。

inline void
pack_arg(datum* d, size_t n, string && t);         // [1]
template <typename X, typename... XS> inline void
pack_args(datum* d, ::size_t n, X&& x, XS&&... xs) // [2]

[1] では、type の引数はstring&&右辺値にのみバインドさstd::moveれ、左辺値から一時 (または d オブジェクト) を区別することができます。右辺値参照は、関数内の左辺値のように動作します。[2] では、テンプレート内にXあり、推論された型であるため、異なる一連の規則が適用さX&&れ、引数に応じて左辺値参照または右辺値参照のいずれかに解決されます。

あなたの場合、引数は実際には一時的なものであるため、X&&にマップされますstd::string&&が、関数内では左辺値として扱われ、バインドできません。これを修正するには、次を追加しstd::forwardます。

template <typename X, typename... XS> inline void
pack_args(datum* d, ::size_t n, X&& x, XS&&... xs)
{
  pack_arg(d, n, std::forward(x));
  pack_args(d, n+1, std::forward(xs)...);
}

std::forwardテンプレートは、引数が左辺値または右辺値参照自体であるかどうかに応じて、左辺値または右辺値参照のいずれかを生成します。

于 2012-09-27T22:03:01.900 に答える