私は現在、std::variant
とC++ 17のカスタム等価物を使用しているコードベースを更新中です。std :: variantを既知の代替方法からリセットする方法はありますか?
バリアントは既知の代替方法からリセットされているため、index()
が現在の値にあると主張するメソッドを提供しますが、依然として無条件に適切なデストラクタを直接呼び出します。
これはいくつかの緊密な内部ループで使用され、パフォーマンス上の影響が(測定された)重要ではありません。これは、問題の代替案が些細な破壊可能なタイプである場合に、コンパイラが破壊全体を排除できるようにするためです。
現時点では、STLの現在のstd::variant<>
実装ではこれを達成できないようですが、私は間違っていると思っています。
これを達成する方法はありますか?私は見ていない、または私は幸運の外ですか?
編集:要求されたとして、ここでは(基礎としての@ TCの例を使用して)使用例です:
struct S {
~S();
};
using var = MyVariant<S, int, double>;
void change_int_to_double(var& v){
v.reset_from<1>(0.0);
}
change_int_to_double
が効果的にコンパイルされます。
@change_int_to_double(MyVariant<S, int, double>&)
mov qword ptr [rdi], 0 // Sets the storage to double(0.0)
mov dword ptr [rdi + 8], 2 // Sets the index to 2
編集#2
@TCの様々な洞察のおかげで、私はこの月に上陸しました腐敗いくつかのデストラクタをスキップして標準に違反しているにもかかわらず、 "動作"します。 https://godbolt.org/g/2LK2fa
// Let's make sure our std::variant implementation does nothing funky internally.
static_assert(std::is_trivially_destructible<std::variant<char, int>>::value,
"change_from_I won't be valid");
template<size_t I, typename arg_t, typename... VAR_ARGS>
void change_from_I(std::variant<VAR_ARGS...>& v, arg_t&& new_val) {
assert(I == v.index());
// Optimize away the std::get<> runtime check if possible.
#if defined(__GNUC__)
if(v.index() != I) __builtin_unreachable();
#else
if(v.index() != I) std::terminate();
#endif
// Smart compilers handle this fine without this check, but MSVC can
// use the help.
using current_t = std::variant_alternative_t<I, std::variant<VAR_ARGS...>>;
if(!std::is_trivially_destructible<current_t>::value) {
std::get<I>(v).~current_t();
}
new (&v) var(std::forward<arg_t>(new_val));
}
偶然によって、変種のすべてのタイプが簡単に破壊可能ですか? – vu1p3n0x
@ vu1p3n0xそれはちょっとテンプレート階層内で掘り下げているので、答えは:時にははい、ときにはいいえです。私はコンパイラが「はい」のケースを処理するかどうかをテストしていませんが、混在しているときに機能するようにしても問題ありません。 – Frank
"*変種は既知の代替品からリセットされています*"それはどういう意味ですか?これを示す古いタイプのコードを提供できますか? –