我正在更新一個代碼庫,目前使用的定製等效物爲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的各種見解,我已登陸這個怪物trosity。它「起作用」,即使它通過跳過一些析構函數而違反了標準。然而,每一個跳過析構函數在編譯時被檢查爲瑣碎所以...:
看到godbolt: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));
}
偶然是所有類型的變體trivially可破壞? – vu1p3n0x
@ vu1p3n0x它有點兒在模板層次結構深處鬆動,所以答案是:有時是,有時不是。我還沒有測試過編譯器是否處理yes情況,但沒關係,因爲我希望它在混合時工作。 – Frank
「*該變體正在從一個已知的替代重置*」這是什麼意思,確切地說?你能否使用你的舊型號提供代碼來證明這一點? –