我正在更新一个代码库,目前使用的定制等效物为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
“*该变体正在从一个已知的替代重置*”这是什么意思,确切地说?你能否使用你的旧型号提供代码来证明这一点? –