Ju Bonn
Ju Bonn

Reputation: 109

Allocate memory for a new object from template argument type

I want to be able to create a new object of type T as illustrated in this code snippet.

template<typename T, typename Arg1, typename Arg2>
void ManageDevice(T& device, Arg1 arg1, Arg2 arg2)
{
    auto newDevice = new T{ arg1, arg2 };
    // ... Perform more operations on newDevice
}

I am currently using the function like this:

CertainClass* device;
ManageDevice(device, arg1, arg2);

The compiler returns the error: Cannot convert from "initializer list" to "class of T*".

I also tried:

auto newDevice = new decltype(device){ arg1, arg2 };

And got the following error:

Error C2464 'class of T*&': cannot use 'new' to allocate a reference

So I removed the reference with this:

using DeviceType = std::remove_reference<decltype(device)>::type;
auto newDevice = new DeviceType{ arg1, arg2 };

And I got the first error message again.

Questions:

  1. Any idea if this is even legal and what could I do to make it work?
  2. In an ideal world I would love to call the function by passing directly a pointer to the class instead of an instance of this class, is it possible?
  3. What would be the name of this?

Upvotes: 2

Views: 1042

Answers (2)

SergeyA
SergeyA

Reputation: 62583

Your factual and template parameters do not match. When the template is written as

template<typename T>
void foo(T& t);

and called with

D* d;
foo(d);

The type of T inside template is going to be D*. Now, if you try

x = new D*{'a', 'b', 'c'};

You will get an obvious compilation error, as there is no (pseudo) constructor for pointer which takes those arguments.

To achieve your goals, you should use

template<typename T, typename Arg1, typename Arg2>
void ManageDevice(T*& device, Arg1 arg1, Arg2 arg2)...

In this case, when called with

Device* device;
ManageDevice(device...);

The actual T inside template would be deduced as Device.

This was written in assumption that you use device as an output parameter. If I guessed, correctly, a better option is to actually return the value, rather than use output parameter:

template<typename T, typename Arg1, typename Arg2>
T* ManageDevice(Arg1 arg1, Arg2 arg2) {
   ...
   return new_device;
}

Then, you can call it as

auto* device = ManageDevice<Device>(a, b);

And while on it, replace T* with unique_ptr<T> and new with std::make_unique.

Upvotes: 3

user7860670
user7860670

Reputation: 37587

It should be ManageDevice(*device, arg1, arg2); so T is deduced to be CertainClass so constructor invocation new T{ will be well-formed. Or, if you are passing a pointer (which probably not a good idea), use std::remove_pointer to get object type from T:

using DeviceType = typename ::std::remove_pointer<T>::type;

Upvotes: 2

Related Questions