Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

storing and re-using decltype value?

if I have a template:

template <class T>
struct Item
{
  T _value;
};

I can then do:

// ...
Item<int> x = { 42 }; // declared as an int

// ...
decltype(x._value) y = 20; // 'y' is also an int

But is it possible to store the decltype to a variable so it can be used later?

Why?
I want to store the values of items as pointer.

Something like std::vector<Item*> but as they are templates I have to store them as pointers to void:

std::vector<void*> is;
is.push_back(new Item<int>());
is.push_back(new Item<double>());
is.push_back(new Item<float>());

And this is all fine, but when it comes time to delete the pointer I need to re-cast my void* back to the proper type (so the destructors are called):

delete (Item<int>*)is[0];

And if I know the type, I could do:

delete (Item<decltype(whatever)>*)is[0];

Hence the reason I would need to store the decltype.

I hope this makes sense.

like image 789
Simon Goodman Avatar asked Aug 13 '16 09:08

Simon Goodman


People also ask

What is the use of decltype in C++?

The decltype type specifier yields the type of a specified expression. The decltype type specifier, together with the auto keyword, is useful primarily to developers who write template libraries. Use auto and decltype to declare a function template whose return type depends on the types of its template arguments.

What is the difference between auto and decltype Auto?

'auto' lets you declare a variable with a particular type whereas decltype lets you extract the type from the variable so decltype is sort of an operator that evaluates the type of passed expression.

Is decltype runtime or compile time?

decltype is a compile time evaluation (like sizeof ), and so can only use the static type.

Should I use decltype?

Another thing to consider is that decltype isn't really necessary unless you're writing library code, auto is nice for everyday programming if you want to make your code more concise, it's up for debate wether using as much auto as possible is good, but it's virtually necessary when working with unutterable types like ...


2 Answers

decltype is a language feature that allows you to retrieve a type at compile-time. It seems that you want to "store" that type so that you can correctly delete objects allocated on the dynamic storage at run-time. Assuming that's the case, decltype is not going to help here.

You have various options:

  1. Use some form of type-erasing facility like Boost.Variant or Boost.Any, as suggested by Baum mit Augen in the comments.

  2. Make your objects part of a polymorphic hierarchy and use smart pointers:

    struct ItemBase 
    {
        virtual ~ItemBase() { }
    };
    
    template <class T>
    struct Item : ItemBase
    {
        T _value;
    };
    
    int main() 
    {
        std::vector<std::unique_ptr<ItemBase>> items;
        items.emplace_back(std::make_unique<Item<int>>());
        items.emplace_back(std::make_unique<Item<float>>());                     
        items.emplace_back(std::make_unique<Item<double>>());
    }
    
like image 106
Vittorio Romeo Avatar answered Oct 11 '22 13:10

Vittorio Romeo


If the problem is only to delete them, you can use unique_ptr with a custom deleter instead of naked pointers.
You don't need to modify your hierarchy to do this.
As an example:

std::vector<std::unique_ptr<void, void(*)(void*)>> is;
is.push_back(std::unique_ptr<void, void(*)(void*)>{new Item<int>(), [](void *ptr) { delete static_cast<Item<int>*>(ptr); }}); 

Even better if using emplace_back instead of push_back:

std::vector<std::unique_ptr<void, void(*)(void*)>> is;
is.emplace_back(new Item<int>(), [](void *ptr) { delete static_cast<Item<int>*>(ptr); }); 

It follows a minimal, working example based on the OP's code:

#include<vector>
#include<memory>

template<typename>
struct Item {};

int main() {
    using Deleter = void(*)(void*);
    std::vector<std::unique_ptr<void, Deleter>> is;
    is.emplace_back(new Item<int>(), [](void *ptr) { delete static_cast<Item<int>*>(ptr); }); 
    is.emplace_back(new Item<double>(), [](void *ptr) { delete static_cast<Item<double>*>(ptr); }); 
    is.emplace_back(new Item<float>(), [](void *ptr) { delete static_cast<Item<float>*>(ptr); }); 
}
like image 37
skypjack Avatar answered Oct 11 '22 14:10

skypjack