だから私は構造体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のタイプに変換できる場合、次のことが発生することです。
- 一時的なtを作成するために、変換コンストラクターが呼び出されます。
setup
この一時的なポインタを格納します。- 一時的なものは破壊されます。
- fは、ハンギングポインタを含むxsで呼び出されます。
g
TSの型に変換可能であるが、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)...);
}
上記で一時的にセットアップが受けられる可能性はありますか?