#How do you deduce the type T from its std::type_info metadata = typeid(T(args...)) ?
81 messages · Page 1 of 1 (latest)
When your question is answered use !solved to mark the question as resolved.
Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.
wdym
template<typename>
struct S;
template<typename T, typename... args>
struct S<T(args...)> {
// use T
};
// ...
S<int(float, char)>
```?
my question technically means how to re-implement std::any manually
in C++11
hm
you know that any_cast we have to check "does this std::any instance contain the type T1 in it or not?"
yeah it does check for that
that's what I am looking for
interesting
the answer there is
template<typename T>
T* any::any_cast()
{
if(typeof(T) == this->metadata)
{
return reinterpret_cast<T*>(this->rawPtr);
}
return nullptr;
}
which is ez
but, deducing what T really is in order to run the destructor of std::any and do CORRECT cleanup with ~T() without leaks
is insane and I don't know how
There has to be compiler magic. But then it doesn't feel right.
It's not that difficult if you know the trick.
struct Any {
void *p;
void (*m_delete_T)(void*);
};
template <class T>
void delete_T(void *p) {
delete reinterpret_cast<T*>(p);
}
Any a;
a.p = new int;
a.m_delete_T = &delete_T<int>;
Obviously you encapsulate the last 2 things into the assignment operator so people can't put different types in there.
you mean void (*m_delete_T)(void*);
but the template instantiations of delete_T will be limited, users of this Any want their own instantiations?
What do you mean?
struct Any {
void *p;
void (*m_delete_T)(void*);
template<typename T>
Any(const T& val) : p(new T(val)), m_delete_T(&delete_T<T>)
{
}
};
this?
template <class T>
void delete_T(void *p) {
delete reinterpret_cast<T*>(p);
}
struct Any {
template <class T>
auto operator=(T &&t) {
p = new T(std::forward<T>(t));
m_delete_T = &delete_T<T>;
}
~Any() {
m_delete_T(p);
}
private:
void *p;
void (*m_delete_T)(void*);
};
Yes
Missing some things obviously, but the important part is there.
and any attempt to fill in a different T will force the C++ compiler to generate the helper function for the deletion, and we take its address
Yup
ummm, what about std::type_info field stored in the Any struct?
to do type checks?
Yeah, to check whether the given T and the stored type match.
T H A T' S S O P O G 
!SOLVED
!solved
Thank you and let us know if you have any more questions!
This thread is now set to auto-hide after an hour of inactivity
oh yeah, also
C devs writing OOP be like "yeah so we need a function pointer in the fields which takes the thisPtr pointer as a first param"
C++ devs writing OOP be like "let's add a public member function with a hidden implicit this parameter"
C++ devs reimplementing Any be like "return to monke, insert the custom deleter as a function pointer field 🐒 "
🤣
Well, you could use std::unique_ptr with a custom deleter instead if you wish to reject 🐒
Seems more complicated though.
nahhhhhhhhhhhhh std::unique_ptr has a different legit mechanism
template<typename T, typename Deleter>
struct uniquePtrCustom
{
T* p;
Deleter d;
};
no void* here
You can probably also abuse std::function to make it somewhat nicer.
nah, that's a type-erased wrapper, I want it manually like you showed
But you can't store a std::unique_ptr<T>.
ye, we know
Well, you can, but you need to type-erase it, which kind of defeats the purpose.
but shared_ptr can be hacked to use shared_ptr<void> p(new T(), CustomDeleter())
Still feels like caveman pointers are the reasonable way to go here.
unga bunga void*
😄
I had to censor this to not allow people to quote me saying "raw owning pointers are the way to go".
who is spying and threatening you? 👀
N-nobody!
-# they are watching
So I still don't get how
shared_ptr_to_base(shared_ptr_to_derived, static_cast<base*>(shared_ptr_to_derived.get()))```
Work..
open gdb and view the internals, no other answer
It says that the control block of derived_ptr is copied that includes the deleter.
I'll do that tomorrow!
Basically the same trick. The std::shared_ptr does not know the type of the deleter.
Which makes sense, since the deleter's signature does not appear in std::shared_ptr's template parameters.
Unlike for std::unique_ptr where it does.
Isn't that like
std::function<void(T*)> del = std::default_delete<T>{};
Alright I see clearer.
Basically, but you change it to void* instead of T*.
Doesn't matter for calling it, but makes it so they are all compatible with each other.
Thanks for the explanation 👍
It's not that much text, but I don't feel like reading through it.
#1287073307627094080 message basically this snippet
showcasing the deleter lifetime
What's with that formatting? Can't even see it all. But I think I get the gist of it.
It's a neat trick. Also comes up elsewhere, like when you make an ECS.
Though often you can make std::function do the work for you.
how is this related to entity component system?
You end up with
struct Entity {
std::size_t entity_id;
~Entity(); //delete all components attached to this Entity
};
so you have to type-erase all the components and delete them somehow.
It's made worse because you have an arbitrary number of components that independently get added or removed.
so like, unordered_map<string, any>
Hold up, casting from T* to void* in the Any constructor, and then casting from void* to T* in the cleanup function pointer, doesn't this violate the strict aliasing rule? Doesn't this trigger undefined behavior?
What can reinterpret_cast docs say about what you have done here?
I remember a rule that pointers are void * roundtrip-castable, meaning you can cast any pointer to void * and back and it'll still work. Meaning void * cannot really be shorter than other pointers.