Alexander Alexander - 1 year ago 64
C++ Question

Template object manager, incorrect argument

I'm attempting to create a simple object manager that holds a list of objects, in main.cpp I'm attempting to put "Target" into the list, however I receive an error: cannot convert argument 1 from 'Target *' to 'int'. I don't understand why the error occurs?

Also, what's the difference between

manager.createObject<Target, 5>()


and

manager.createObject<Target>(5)


are they the same, i.e. am I calling the function correctly?

// ObjectManager.h
class ObjectManager
{
std::vector<std::shared_ptr<Object>> objects; // list of all objects
public:
template<class T, typename... Args>
std::shared_ptr<T> createObject(Args&&... args) {
std::shared_ptr<T> new_ptr = std::make_shared<T>(new T(std::forward<Args>(args)...));
objects.emplace_back(new_ptr);
return new_ptr;
}
}


// Target.h
class Target
{
public:
int value;
Target(int _value) : value(_value) {}
};

// main.cpp
int main()
{
ObjectManager manager;
std::shared_ptr<Target> t = manager.createObject<Target>(5);
std::cout << t->value;
}


EDIT: the 'Object' object in ObjectManager was part of my implementation code and should not have been part of this example here - it should have simply been Target

Answer Source

There are many errors in your code. I'll start somewhere.

  • There is a missing Object class. Either you didn't included it in this example or you are using a undefined identifier.
  • ObjectManager class definition is missing a ;
  • It seems Target is not extending from Object. Are you sure a std::shared_ptr<Target> is convertible to a std::shared_ptr<Object>? I think not.
  • You misunderstood how to use std::make_shared. It doesn't take a pointer as parameter, but your class's constructor parameter. The correct usage is std::make_shared<T>(std::forward<Args>(args)...). Just as the error says, your class is not constructible from a Target*, but from a int.

There maybe other problems I didn't spotted.


Now, to the second part of the question.

You seem to have a confusion between function parameters and template parameters. Both are distinct things.

Template parameters are like arguments to the implementation of the function. There are compile time entities. This is why you can send types there, because types are compile time entities. To have a function callable like this:

foo<Bar, 5>();

You must have a definition like that:

template<typename T, int n>
void foo() {}

As the function definition says, the template parameters are a type, and a integer. You can see from the way the function is called that you must send template parameter as template parameter. Function parameters are the arguments listed in (...). If we add some parameter to our function, it would look like this:

template<typename T, int n>
void foo(const char*, int) {}

foo<Bar, 4>("baz", 7);

As you can see, both function parameters and template function parameters are different, separated things.

What about deduction?

Template arguments deduction is the process of letting the compiler deduce by itself what the template parameters are. I won't go into the whole process, but it look like this:

template<typename T>
void foo(T t) {}

foo(4); // deduce T as int

As such, you won't need to tell that the T parameter is int.

am I calling the function correctly?

This is the correct way indeed:

manager.createObject<Target>(5)

It will call the create object with the template parameter T as Target, and ... Args deduced as int. There is no int template parameters, only type template parameters.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download