Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Instantiate non-template class with templated constructor

Tags:

c++

templates

I have a small C++ class which wraps type information for some basic types; a simplified version looks like this:

struct TypeInfo {
    TypeInfo(std::size_t elm_size, const std::string& type_name) : 
        elm_size(elm_size), 
        type_name(type_name)
    {}

    std::size_t elm_size;
    std::string type_name;    
}


TypeInfo double_info(sizeof double, "double");
TypeInfo int_info(sizeof int, "int");

This works - but I would love to be able to instantiate the TypeInfo object based on normal C++ templating; i.e. something like this:

TypeInfo<double> double_info; // <- This does not work

Since the class as such does not contain any T - it is not really a templated class - but rather a convenient instantiation method. When this is contained in a function which is truly templated:

void vector_operation(const std::vector<T>& data) {
    TypeInfo<T> type_info;  // <- This does not work!
}

it would be really helpful if I could instantiate TypeInfo instance based on a template parameter. Since I only need to cover a handful of fundamental types - float, double, int and char I would be more than happy to specialize the handful of types explicitly.

Update: @nathan_oliver suggested to make the class as a whole a template, and then use sizeof(T) to determine the element size. The problem with that solution (as I see it) - is that the user still needs to supply the type_name string (and some more type specific information) - I would like specialize the few types I need - and then fully specify:

template <typename T>
struct TypeInfo {
    TypeInfo();

    std::size_t elm_size;
    std::string type_name;
}

And then in the .cpp file:

template<>
TypeInfo::TypeInfo<double>() {
     this->elm_size = sizeof(double);
     this->type_name = "double";
}


template<>
TypeInfo::TypeInfo<int>() {
    this->elm_size = sizeof(int);
    this->type_name = "int";
}

but this does not even compile:

type_info.cpp:46:5: error: 
invalid use of template-name ‘TypeInfo’ without an argument list
     TypeInfo::TypeInfo()
like image 332
user422005 Avatar asked Mar 16 '26 11:03

user422005


2 Answers

You cannot specify template parameters for a constructor. They can only be deduced. You could send a type tag to your constructor:

template<typename> struct tag_t {};
template<typename T> inline constexpr auto tag = tag_t<T>{}; 

struct TypeInfo {
    template<typename T>
    TypeInfo(tag_t<T>) :
        elm_size{sizeof(T)},
        type_name{/* find a way to get name */} {}

    std::size_t elm_size;
    std::string type_name;  
};

TypeInfo double_info{tag<double>};
TypeInfo int_info{tag<int>};

You'll have to find a way to get the name of a type from a template argument. Some libraries exists for that like ctti

like image 171
Guillaume Racicot Avatar answered Mar 18 '26 01:03

Guillaume Racicot


If you're indeed only interested in a handful of fundamental types, and can specialize them manually it seems like a good way to go.

template <typename T>
struct TypeInfo; // default values could go here for un-specified types

template <>
struct TypeInfo<int> {
    const std::size_t elm_size = sizeof(T);
    const std::string type_name = "int";
}

// more specializations for double, char and float

Then you can go ahead and use it by just instantiating with a template parameter.

If the fact that different instatiations of TypeInfoare different types is a problem, you could use a function that return a common TypeInfo object with the right values set based on the parameter passed to the function.

template <typename T>
TypeInfo get_type_info() {
    return TypeInfo{sizeof(T), "unknown"};
}

template <>
TypeInfo get_type_info<int>() {
    return TypeInfo{sizeof(T), "int"};
}

auto type_info = get_type_info<int>();
like image 35
super Avatar answered Mar 17 '26 23:03

super



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!