C++ - Use Class Name As Function Parameter - c++

Say I have list of of classes called ItemOne, ItemTwo, ItemThree and ItemFour, which are all subclasses of ItemBase.
I would like to have a constructor in another class called ItemGenerator that accepts the name of any of these classes. How would I do this?
ItemGenerator *someItem = new ItemGenerator(ItemThree);
Another option would be to pass a static function on one of these classes, but again, I have no idea how to do that.
ItemGenerator *someItem = new ItemGenerator(ItemOne::start());
Thanks.

You could use a template:
struct ItemBase {virtual ~ItemBase();};
struct ItemOne : ItemBase {};
struct ItemTwo : ItemBase {};
struct ItemThree : ItemBase {};
struct ItemFour : ItemBase {};
struct ItemGeneratorBase {
virtual unique_ptr<ItemBase> generate() {}
virtual ~ItemGeneratorBase() {}
};
template<typename Item>
struct ItemGenerator : ItemGeneratorBase {
virtual unique_ptr<ItemBase> generate() {
return unique_ptr<ItemBase>(new Item());
}
};
std::unique_ptr<ItemGeneratorBase> someItem(new ItemGenerator<ItemThree>());

Do you really want to pass the name, i.e. a string? Then you'd have to provide the Item*-classes with a corresponding function, e.g.
class ItemOne {
static std::string name();
};
ItemGenerator *someItem = new ItemGenerator(ItemThree::name());
Or are you looking for templates? You have different possibilities there: make a class template, maybe derived from an ItemGenerator base class:
class AbstractItemGenerator { /* ... */ };
template <class Item>
class ItemGenerator {
ItemGenerator();
};
ItemGeneratorBase *someItem = new ItemGenerator<ItemTwo>();
Or make only the construtor templated - you cannot explicitly specify the parameter, so use argumet deduction:
//take 1: use pointers
class ItemGenerator {
template <class Item>
ItemGenerator(Item* dummy);
};
ItemGenerator *someItem = new ItemGenerator((ItemFour*)NULL);
//take 2: use a tag struct
template <class I>
struct ItemTag{};
class ItemGenerator {
template <class Item>
ItemGenerator(ItemTag<Item> tag);
};
ItemGenerator *someItem = new ItemGenerator(ItemTag<ItemOne>());
I am not sure if one of these suits your needs. Maybe elaborate what you want to use this for.

Function cannot accept name of a class as a parameter, as class is not an object in C++.
But template-function can be parametrized by a class name.
Something like this:
template<class T>
ItemGenerator* ItemGeneratorFactory() { T::start(); ...}
ItemGenerator *someItem = ItemGeneratorFactory<ItemThree>();

As the other answers indicate, you can achieve using templates.
Just to offer another idea, you can pass a function pointer that creates an instance of whatever you want (or whatever it is you want to do with that class)
ItemGenerator(ItemClassPtr itemClassFn)
{
void * myObject = itemClassFn();
}

I'm a little rusty, but I'm pretty sure you could just put ItemBase in the constructor and it would accept all subclasses.
ItemGenerator::ItemGenerator(ItemBase base){\\do something with base
}
or, if that and using a template don't work, you could create multiple constructors:
ItemGenerator::ItemGenerator(ItemOne one){}
ItemGenerator::ItemGenerator(ItemTwo two){}
...

This is exactly what the Factory design pattern does.
Basically there is a static method in the ItemGenerator class that can return pointers to ItemBase objects, but can return pointers to Item1, Item2 etc depending on the parameters to the static method.
For instance, in the ItemGenerator class,
static ItemBase *Generate( <any parameter> )
{
switch (parameter)
{
case Value1: return new Item1();
...
...
}
}

It is difficult to find a solution to your problem without knowing the purpose of ItemGenerator.
As Mankarse says, one solution would be to use a template to pass your class to the generator.
Nevertheless, if ItemGenerator cannot be templated or if you do not want to use the templates here, you can still pass a function as you suggest by using either std::function or boost::function.
There are also some libraries that can help you to add reflexion to c++. I remember of CAMP but I do not know if it is still active. You may find a solution for your problem there.

Related

Create a templated variable within a templated class of a different type

I'm not sure what I am asking for is possible.
I have a templated class called Controller. This is a variadic template class which takes multiple classes and can set their values as such.
Controller<ClassA,ClassB,ClassC>* myController = new Controller<ClassA,ClassB,ClassC>(*a,*b,*c);
myController->setValues(32);
This takes a bunch of different classes together and allows me to to set their values at the same time. setValues is a templated function which allows any type to be passed in. However, right now I am trying to modify my class so that I can set a value within the controller itself for easy retrieval. However this is the part that is proving difficult.
template<typename...Classes>
class Controller
{
public:
Controller(Classes&...objects) : objects(objects...){}
Controller(std::tuple<Classes&...> tup) : objects(tup){}
template<typename T>
void setValues(T value)
{
std::apply([&](auto&...x) { x.updateValue(value),...);}, objects); //calls the updateValue function for each class
}
private:
std::tuple<Classes&...> objects;
};
I want to add the following as a private variable T controllerValue; However, I know that I cannot simply declare T because we cannot define member templates and the compiler has no idea what to expect. Which then I tried to create a private struct:
template<typename T>
struct ControllerValue { T value; };
However, I cannot define a struct underneath that, because the same problem occurs. The compiler has no idea what type ControllerValue is. What I would like is something like this:
template<typename...Classes>
class Controller
{
public:
Controller(Classes&...objects) : objects(objects...){}
Controller(std::tuple<Classes&...> tup) : objects(tup){}
template<typename T>
void setValues(T value)
{
thisValue.value = value;
std::apply([&](auto&...x) { x.updateValue(value),...);}, objects); //calls the updateValue function for each class
}
template<typename T>
T getValue() const { return thisValue.value }
private:
std::tuple<Classes&...> objects;
template<typename T>
struct ControllerValue { T value; };
ControllerValue thisValue;
};
This will not compile at all for the same reason that the compiler has no idea what type ControllerValue should be. And this is where I am stuck. Is this even possible to do? If not, what is another way that I can make this work?
To clear up confusion, the use case would be something like this:
Controller<ClassA,ClassB,ClassC>* myController = new Controller<ClassA,ClassB,ClassC>(*a,*b,*c);
myController->setValues(32);
int commonValue = myController->getValue();
or
Controller<ClassA,ClassB,ClassC>* myController = new Controller<ClassA,ClassB,ClassC>(*a,*b,*c);
myController->setValues(32.3);
double commonValue = myController->getValue();
I think solving this exact problem is impossible in C++ (and still very cumbersome in languages with runtime generics). You can very easily create a polymorphic class that can only store any value:
class PolymorphicBase
{
public:
virtual ~PolymorphicBase() = default;
};
template <class T>
class PolymorphicObject : public PolymorphicBase
{
T value;
public:
PolymorphicObject(T value) : value(std::move(value))
{
}
};
A member of std::unique_ptr<PolymorphicBase> can sufficiently store any value, but how would such a value be retrieved? Probably the easiest is to expose the reference to PolymorphicBase and use dynamic type checks to see if the type is compatible with something you know, but what if you need the code to work for any type?
This is what lambdas with auto parameters are useful for. However, you would have to be able to pass such a lambda to a method on PolymorphicBase and implement that method in PolymorphicObject. This is impossible, since you cannot override a method template (it needs to be a template to accept a lambda) – that's where the compile-time and runtime parts of C++ clash. And there is simply no type in C++ that represents a function accepting any parameter (and knowing its type), which is a template by itself.
You can partially solve this by making the type of the lambda known to PolymorphicBase:
template <class Retriever>
class PolymorphicBase
{
public:
virtual void retrieve(Retriever func) = 0;
virtual ~PolymorphicBase() = default;
};
template <class Retriever, class T>
class PolymorphicObject : public PolymorphicBase<Retriever>
{
T value;
public:
PolymorphicObject(T value) : value(std::move(value))
{
}
void retrieve(Retriever func) override
{
func(value);
}
};
auto lambda = [](auto arg)
{
std::cout << arg << std::endl;
};
PolymorphicObject<decltype(lambda), int> obj(6);
PolymorphicBase<decltype(lambda)> &ptr = obj;
ptr.retrieve(lambda);
This is useful if you ever have only a single way to retrieve the value.
I don't think this is needed in most cases anyway. Usually you use a fixed set of types as the values, so you can use a variant there, or they all implement a common interface, or (as you've pointed out in the comments) you actually meant to move the type parameter from the method to the class (which allows you to check that all the types actually support the value earlier than originally).
However, I agree that in languages with generics/templates it is somewhat hard to have a method that can actually choose its result type in a generic fashion, without being controlled by outside parameters.

C++/(Qt) pointer to any object with specific method

How do I do to call a specific method present on all classes from an other (TranslationManager) class ?
I simplified a lot the code. I just want to call the setTranslationText of any class from TranslationManager.
These are to take in consideration:
All classes have a setTranslationText method
We should call setTranslationText of any class from TranslationManager by using the pointer to the class
class Interface
{
...
public:
void setTranslationText(QString translatedString);
}
class AnyOtherInterface
{
...
public:
void setTranslationText(QString translatedString);
}
...
…
Translationmanager::Translationmanager(){
AnyClass = Interface; // Pointer to Interface Class
AnyClass->setTranslatioNText("Text");
AnyClass = AnyOtherInterface; // Pointer to AnyOtherInterface Class
AnyClass->setTranslatioNText("AnotherText");
}
…
You could use a template
template <typename T>
void setTranslationText(T* t, const QString &translatedString)
{
t->setTranslationText(translatedString);
}
That way you wouldn't need an interface class just to inherit for this one (or however many) methods. Then the template would only compile if for a given class instantiation they had a setTranslationText method defined. The way you'd use it is
Translationmanager::Translationmanager()
{
setTranslationText(Interface, "Text"); // Pointer to Interface Class
setTranslationText(AnyOtherInterface, "AnotherText"); // Pointer to AnyOtherInterface Class
}
Adding to Cory's answer: If you're using C strings to initialize QString, you shouldn't depend on the implicit conversion - instead, make your use case explicit:
template <typename T>
void setTranslationText(T* t, const char *translatedString) {
t->setTranslationText(QString::fromUtf8(translatedString));
}
I wasn't precise about what I wanted. I finally found the best solution to my problem: callback.
Solution found on: C++ class member callback simple examples
std::vector<std::function<void(std::string,std::string)>> callbacks;
template<class T> void addTranslationText(T* const object, void(T::* const mf)(std::string,std::string)){
using namespace std::placeholders;
callbacks.emplace_back(std::bind(mf, object, _1, _2));
}
...
// Call callback
callbacks.at(0)(std::string("arg1"), std::string("arg2"));

Create "new instance of object" method in C++

Is there a way to create an instance of a class, from that class, without using templates?
I need to do somethink like
static classobj* classobj::create (){return new this;}
Now I use class template and pass to template type of creatable class like :
template<class T>
class basic_class {
public:
static T *create(int param) { return new T(param); }
}
and
class A : public basic_class<A> {}
Why not this?
return new classobj;
Or this:
return new decltype(*this);
But please don't do this at all. The pointer returned by your function has unclear ownership semantics. We generally don't need raw pointers nowadays.
If I understand your question correctly, you want to create a non-template class like this:
class Base
{
public:
static (Magic)* create() { return new (Magic); }
}
We would then call this method thusly:
class Derived : public Base {};
Derived* object = Derived::create();
And the question is: what incantation do we substitute for "(Magic)?" Unfortunately, there is no such syntax. Static class methods are just like regular functions. All types involved must be known at the point the function is declared.
Can you elaborate on why you don't want to use templates? Perhaps there's another way to solve your problem.
If I understand your question correctly, then you have to add static create to every class:
class A
{
public:
//to create
static A* create(int param) { return new A(param); }
};
and then do this:
A* ptr = A::create(4);
or better, avoiding memory leaks
std::unique_ptr<A> uptr(A::create(4));
Or, if your issue is to make a "smart" create in the basic_class for any constructor, then do this in C++11:
template <class T>
class base_class
{
public:
template<typename... Params>
static T* construct(Params&&... parameters) { return new T(std::forward<Params>(parameters)...); }
};
class A : public base_class<A>
{
public:
A(const std::string& s) {}
A(int i) {}
};
and so
A::create(std::string("Hey"));
A::create(5);
both work now.
Edit: Base class defines "construct" method. So the above should be
A::construct(std::string("Hey"));
A::construct(5);
Implement a copy constructor first
classobj(const classobj& obj);
then
return new classobj(*this)

alternative to virtual typedef

I have an interface IEnumerable for template classes of List<>, Array<> and Dictionary<>. I was hoping to use typedef to get their templated types T.
I was hoping to do the following.
class IEnumerable
{
public:
virtual typedef int TemplateType;
}
And then override in inherited member, but you cant make a virtual typedef. So is there any other way that i could get the type of an unknown template class (IEnumerable is not template)?
Well, here is what is discussed in the comments in case somebody with the same question later finds this.
Basically, you want to do something similar to C#'s List<>, Array<>, IEnumerable and IEnumerator. However, you don't want to have to create a generic parent class Object because it may mean that you'll need to dynamic_cast every time.
Additionally, you don't want to make IEnumerable a template because you don't want to have to know the type when using the collection.
In fact, with C++11, you can make IEnumerable a template and not have to know the type by using the implicit type keyword auto, which is the C++11 equivalent of c#'s var keyword.
So to do this, what you can do is:
template <class T>
class IEnumerable {
public:
virtual IEnumerator<T> getEnumerator() = 0;
// and more stuff
}
then
template <class T>
class List : public IEnumerable<T> {
public:
virtual IEnumerator<T> getEnumerator() {
return ListEnumerator<T>(this);
}
}
and
template <class T>
class ListEnumerator : public IEnumerator<T> {
public:
T getNext(); // or something to this effect
// and more stuff
}
Finally, when it comes to using it, you can do:
List<int> myList;
auto i = myList.getEnumerator();
int z = i.getNext()+1;

Factory pattern and class templates in C++

I have a hierarchy of class templates. At the top of the hierarchy is an abstract base class (interface). I won't know which concrete implementation to instantiate until runtime, so it seems like the perfect situation to use the factory pattern. However, virtual member function templates are not allowed in C++.
How can I achieve a legal design similar to the below in C++?
The individual concrete implementations of the IProduct interface as well as the concrete factories will live in different dynamic libraries, one or more of which will be loaded at runtime.
template<class T> class IProduct
{
public:
virtual void doWork(const T & data) = 0;
};
template<class T> class ProductA : public IProduct<T> {/*...*/};
template<class T> class ProductB : public IProduct<T> {/*...*/};
class IProductFactory
{
public:
template<class T> virtual IProduct<T> * createProduct() = 0;
};
class ProductAFactory: public IProductFactory
{
public:
template<class T> virtual IProduct<T> * createProduct()
{
return new ProductA<T>;
}
};
class ProductBFactory: public IProductFactory
{
public:
template<class T> virtual IProduct<T> * createProduct()
{
return new ProductB<T>;
}
};
Why can't you templatize IProductFactory on T as well? That would get rid of your error, and it's no less general. The client is still going to have to know what T is in order to call thecreateProduct method.
Edit Re: comment
In order to do this, you will need to just create a templatized function to create the factory. So:
template<class T> IProductFactory<T>* getProductFactory();
Now your factory is templatized, the createProduct method is no longer a member template. Not sure what your criteria is for returning a ProductAFactory vs. a ProductBFactory but you will either have to pass in a string to choose, have this be a member function of another class that would make the decision, or have multiple free functions but only expose one version or another to a particular client.
This doesn't need a template. Does that eliminate your problem?