Retrieving size of datatype from std::type_info
Asked Answered
S

1

10

In C++03, when you use the operator typeid, a type_info object is returned.

Is it possible to retrieve the size of the given type based only on this result, such as returned by the sizeof operator?

For example:

std::type_info info = typeid(int);
int intSize = sizeof(int);
int intSize2 = info.getSize(); // doesn't exist!

The issue is that we use a third-party multi array class that gives back a type_info, but not the size of the type.

Simaroubaceous answered 17/12, 2014 at 10:0 Comment(4)
Why not just use the type directly? What are you trying to accomplish that requires this?Tobacconist
We use a third-party multi array class that gives back a type_info, but not the size of the type.Simaroubaceous
There is no such facility as far as I can see...Soerabaja
I was afraid so, just asked because I've been searching online and couldn't find any resources confirming it.Simaroubaceous
W
2

The best way I can see (I would like to be proven wrong) is to register the types beforehand, like this:

#include <typeinfo>
#include <iostream>
#include <stdexcept>
#include <map>
#include <vector>

typedef std::map<const std::type_info*, std::size_t> sizes_container; // we cannot use std::type_index, but that's ok - typeid returns const std::type_info&, which refers to an object which lives during the entire lifetime of the program

sizes_container& sizes() // wrapped in a function to avoid static initialization order fiasco
{
    static sizes_container s;
    return s;
}

template<typename T>
void register_size() // Register the type. Can be called multiple times for the same type.
{
    sizes().insert(sizes_container::value_type(&typeid(T), sizeof(T)));
}

class no_such_type : public std::domain_error
{
public:
    no_such_type(const std::string& str) :
        std::domain_error(str)
    {

    }
};

std::size_t get_size(const std::type_info& typeinfo)
{
    sizes_container::iterator it = sizes().find(&typeinfo);
    if(it != sizes().end())
    {
        return it->second;
    }
    else
    {
        throw no_such_type(std::string("No type ") + typeinfo.name() + " registered");
    }
}

int main()
{
    register_size<int>();
    register_size<std::vector<int> >();

    std::cout << get_size(typeid(int)) << "\n" // get the size from std::type_info, possibly at runtime
              << get_size(typeid(std::vector<int>)) << "\n" << std::flush;
    std::cout << get_size(typeid(long)); // if the type isn't registered, the exception no_such_type is thrown
}

Possible output:

4
24

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
terminate called after throwing an instance of 'no_such_type'
  what():  No type l registered

If you can control how you create the arrays (for example, with a factory method) you can directly register the type here.

Waddle answered 17/12, 2014 at 16:17 Comment(3)
IIRC, there is no guarantee that all calls to typeid with the same type return the same instance of type_info. So type_info should not be compared by it's address. To workaround this type_index was added in C++11. If you cannot use C++11 write your own wrapper.Tayler
According to magras, using the string typeinfo::name() instead of address the should be portable and consistentOffoffbroadway
No, the above message did not say that. Also this is simply not true.. It's been 13 years since C++11, just use std::type_index.Waddle

© 2022 - 2024 — McMap. All rights reserved.