c++ - Is there a way to reset a std::variant from a known alternative? -


i'm in process of updating codebase using custom equivalent of std::variant c++17 .

in parts of code, variant being reset known alternative, class provides method asserts index() @ current value, still directly invokes proper destructor unconditionally.

this used in tight inner loops, , has (measured) non-trivial performance impact. that's because allows compiler eliminate entire destruction when alternative in question trivially destructible type.

at face value, seems me can't achieve current std::variant<> implementation in stl, i'm hoping i'm wrong.

is there way accomplish i'm not seeing, or out of luck?

edit: requested, here's usage example (using @t.c's example basis):

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 compiles effectively:

@change_int_to_double(myvariant<s, int, double>&)   mov qword ptr [rdi], 0       // sets storage double(0.0)   mov dword ptr [rdi + 8], 2   // sets index 2 

edit #2

thanks various insight @t.c., i've landed on monstrosity. "works" though violate standard skipping few destructors. however, every skipped destructor checked @ compile-time trivial so...:

see on godbolt: https://godbolt.org/g/2lk2fa

// let's make sure our std::variant implementation nothing funky internally. static_assert(std::is_trivially_destructible<std::variant<char, int>>::value,            "change_from_i won't 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 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 fine without check, msvc can      // use 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)); } 

#include <variant> struct s {     ~s(); }; using var = std::variant<s, int, double>;  void change_int_to_double(var& v){     if(v.index() != 1) __builtin_unreachable();     v = 0.0; } 

gcc compiles function down to:

change_int_to_double(std::variant<s, int, double>&):   mov qword ptr [rdi], 0x000000000   mov byte ptr [rdi+8], 2   ret 

which optimal. clang's codegen, otoh, leaves desired, although isn't bad if use std::terminate() (the equivalent of assertion) rather __builtin_unreachable():

change_int_to_double(std::__1::variant<s, int, double>&): # @change_int_to_double(std::__1::variant<s, int, double>&)   cmp dword ptr [rdi + 8], 1   jne .lbb0_2   mov qword ptr [rdi], 0   mov dword ptr [rdi + 8], 2   ret .lbb0_2:   push rax   call std::terminate() 

msvc...let's not talk msvc.


Comments

Popular posts from this blog

Sort a complex associative array in PHP -

vb.net - How to ignore if a cell is empty nothing -

recursion - Can every recursive algorithm be improved with dynamic programming? -