You firstly use the Identifier(Args...) constructor, then you use the other one twice.
template< typename ... T >
requires std::convertible_to< std::tuple< Args... >, std::tuple< T... > >
Identifier( const Identifier< T... >& identifier ): std::tuple< Args... >(static_cast< std::tuple< T... > >(identifier))
{}
When item is passed to it, firstly a const Identifier<T...>& to it is created as argument to the constructor. Then this reference is static_casted to a std::tuple<T...>.
Note that T... is std::wstring, int64_t, as this is items bases templated types.
This means that you cast away the reference, resulting in a temporary copy of the original item. Then you assign that copy's std::wstring member to a const std::wstring& via the construction of the base. After the construction, the temporary gets destroyed, leaving the object referencing an already deleted std::wstring.
To solve your problem you could e.g. just drop the static_cast and pass the argument as is.
As @TedLyngmo mentioned here, you most likely have the order of the std::convertible_to reversed.
It should be
// std::convertible_to<From, To>;
std::convertible_to<std::tuple<T... >, std::tuple<Args...>>
Which could be further modified to the following:
Identifier(std::convertible_to<std::tuple<Args...>> auto&& identifier)
: std::tuple<Args...>(std::forward<decltype(identifier)>(identifier)) {}
This uses std::forward on the forwarding reference to perfectly forward any arguments you pass to it. You could apply this to the other constructors as well.
I got invalid value in string reference in element in vector and invalid value in string reference in item_ref.
How do you know? Did you print the values to std::wcout? Well, at least I tried to do this and (depending on how I compiled it) I got either garbage output or even a crash.
I suggest you enable all warnings (I still got none) and enable other tools like -fsanitize=undefined which resulted in the following:
UndefinedBehaviorSanitizer:DEADLYSIGNAL
==1==ERROR: UndefinedBehaviorSanitizer: stack-overflow on address 0x7ffd94afc000 (pc 0x7ee02548a31e bp 0x59c5bf4e1e6b sp 0x7ffd94afb190 T1)
#0 0x7ee02548a31e in __gnu_cxx::stdio_sync_filebuf<wchar_t, std::char_traits<wchar_t>>::xsputn(wchar_t const*, long) (/opt/compiler-explorer/gcc-14.2.0/lib64/libstdc++.so.6+0x12331e) (BuildId: 998334304023149e8c44e633d4a2c69800a2eb79)
#1 0x7ee0254b65e4 in std::basic_ostream<wchar_t, std::char_traits<wchar_t>>& std::__ostream_insert<wchar_t, std::char_traits<wchar_t>>(std::basic_ostream<wchar_t, std::char_traits<wchar_t>>&, wchar_t const*, long) (/opt/compiler-explorer/gcc-14.2.0/lib64/libstdc++.so.6+0x14f5e4) (BuildId: 998334304023149e8c44e633d4a2c69800a2eb79)
#2 0x59c5bf4e11c7 in main /app/example.cpp:35:15
#3 0x7ee025029d8f (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: 490fef8403240c91833978d494d39e537409b92e)
#4 0x7ee025029e3f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e3f) (BuildId: 490fef8403240c91833978d494d39e537409b92e)
#5 0x59c5bf4b4494 in _start (/app/output.s+0xa494)
SUMMARY: UndefinedBehaviorSanitizer: stack-overflow (/opt/compiler-explorer/gcc-14.2.0/lib64/libstdc++.so.6+0x12331e) (BuildId: 998334304023149e8c44e633d4a2c69800a2eb79) in __gnu_cxx::stdio_sync_filebuf<wchar_t, std::char_traits<wchar_t>>::xsputn(wchar_t const*, long)
==1==ABORTING
id
https://godbolt.org/z/5eja84EaM
Identifier<std::wstring, int64_t>andIdentifier<const std::wstring&, int64_t>are different unrelated types. Makes me think that onitem_ref = item, maybe the compiler is making a temp copy, and you are taking a reference to the temp, and then the temp is gone by the time you reach theemplace_back(). You should use your debugger to verify the actual flow, look at the memory addresses involved, etc.std::convertible_toare backwards.static_cast< std::tuple< T... > >(identifier)This creates a temporary copy ofidentifier. You might have meantstatic_cast< const std::tuple< T... >& >(identifier). Or drop the cast entirely, things should work without.tuple. You are treading on thin ice.