2

だから私は構造体Xを持っています:

struct X
{
    int typecode;
    char* pData;
    int length;
    ...
}

タイプの長いリストから、このセットをTSと呼びます。TSには、ほとんどのプリミティブ型といくつかのクラス型が含まれます。

TSのタイプTごとに、通常の関数が定義されています。

void setup(X& x, const T& t);

たとえば、T=文字列の設定は次のようになります。

void setup(X& x, const string& s)
{
    x.typecode = X_STRING;
    x.pData = s.c_str();
    x.length = s.size();
    ...
}

これで、テンプレート関数convert_to_xができました。

template<class T>
X convert_to_x(const T& t)
{
    X x;
    memset(x, 0, sizeof(x));
    setup(x, t);
    return x;
}

そして、Xの配列を取る関数f:

void f(X* xs, int num_args);

さらに、可変個引数テンプレート関数g

template<class... Args)
void g(Args... args)
{
    constexpr num_args = sizeof...(args);

    X xs[] = { convert_to_x(args)... };

    f(xs, num_args);
}

何が起こっているのかというと、gを任意の数のパラメーターとタイプで呼び出すことができ、パラメーターをXタイプの配列に変換してから、fを呼び出すことができます。

問題は、gがTSにないタイプで呼び出されたが、TSのタイプに変換できる場合、次のことが発生することです。

  1. 一時的なtを作成するために、変換コンストラクターが呼び出されます。
  2. setupこの一時的なポインタを格納します。
  3. 一時的なものは破壊されます。
  4. fは、ハンギングポインタを含むxsで呼び出されます。

gTSの型に変換可能であるが、TSの型ではない引数を変換し、のスコープ全体でそれらを保持するためのエントリの方法が必要ですg

これを達成するための最良の方法は何ですか?

アップデート:

私がちょうどそれがうまくいくかもしれないと思った1つの方法はconvert、TSの各タイプTの通常の関数を次のように定義することです。

T convert(const T& t) { return t; }

次に、gのラッパーを定義します。

template<class... Args>
void g2(Args... args)
{
    g(convert(args)...);
}

しかし、これにより、すでにTSにあり、変換する必要のないタイプの不要なコピーが発生すると思います。これを回避するために右辺値/左辺値のセマンティクスを使用する方法はありますか?

アップデート2:

多分これはうまくいくでしょう:

TSの各Tについて:

const T& convert(const T& t) { return t; }
T convert(const T&& t) { return t; }

それから:

template<class... Args>
void g2(Args... args)
{
    g(convert(args)...);
}

上記で一時的にセットアップが受けられる可能性はありますか?

4

1 に答える 1

1

次の削除されたオーバーロードを追加できますsetup

void setup(X& x, const string& s) = delete;

右辺値参照は、const 左辺値参照よりも簡単に一時変数にバインドされるため、一時変数を使用して呼び出すsetupと、右辺値参照を含むオーバーロードが選択されます。しかし、このsetupオーバーロードは削除されているため、実際に呼び出すのは違法です。そのgため、 が間違った型の引数で呼び出された場合、行はの削除されたバージョンを呼び出すX xs[] = { convert_to_x(args)... };必要があるため、インスタンス化は失敗します。次に、特定のインスタンス化も失敗します。convert_to_argssetupg

編集

アップデート #2 を見ると、これでうまくいくはずです。convertのいずれかへの最適な変換がすでに行われているためTSg不要な型で呼び出されてはなりません。したがって、 の呼び出し時に不要な変換によって一時変数が作成されることはありませんsetup。したがって、一時オブジェクトは への引数となりg、 の期間存続することが保証されgます。

編集 2

T convert(const T&& t) { return t; }その結果、値が不必要にコピーされる可能性があります。しかし、これは簡単に修正できます。

const T& convert(const T& t) { return t; }
const T&& convert(const T&& t) { return std::move(t); }

値のコピーは取得されません。一時変数は、それらが作成された完全な式の終わりまで存続するため、一時変数の有効期間も正しいです。

template<class... Args>
void g2(Args... args)
{
    g(convert(args)...);
} //          ^^^^ temporaries created by a conversion here will live until g returns
于 2012-08-20T02:00:21.377 に答える