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

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"));

Related

How can I easily redirect a Base method to an identical Derived class method?

In working with a framework (Godot) that uses a register_method(<name>, <pointer_to_method>) to register a c++ method to a scripting API.
this method however doesn't support pointer to template classes.
So in the example:
static void _register_methods() {
register_method("my_method", &TMyClass::my_method); // this fails
// ^ template class
register_method("my_method", &MyClass::my_method); // this works
// ^ normal class
}
I have a template class TExample and an Example that extends the template class. The methods declarations and method definitions are all inside the TExample (however the methods are registered in Example).
So when I do:
register_method("my_method", &Example::my_method); // this fails because it is referencing the method of the parent class (template).
What I've found that works is redirecting the methods to "local" methods.
class Example : TExample<...>
{
public:
void my_method() {
TExample::my_method();
}
static void _register_methods() {
register_method("my_method", &Example::my_method); // this works
}
}
But imagine I have like 50 methods every time I want to create a new class from the template I need to redirect 50 methods. is there a shortcut to do this?!
Not sure what you mean by "this fails".
It just works, look (live demo):
template<class T>
class TExample {
public:
void my_method() {}
};
class Example : TExample<int> {
template<class U>
static void register_method(U u) {
}
public:
static void register_methods() {
register_method(&Example::my_method); // it works
register_method(&TExample::my_method); // this also works
}
};
int main()
{
Example ex;
ex.register_methods();
}
Now if you want to access my_method() from outside the class, then you should inherit publicly:
class Example : public TExample<...>
{
Then Example::my_method() will also work outside.
Note: TExample is not a template class, but a class template. However, in the context of a template instantiation (inside the definition of Example) the template arguments are substituted automatically.
Since template classes will be created for the types you are using you should mention the type also.
register_method("my_method", &TMyClass<Type>::my_method);
What about using a lambda ?
Does:
register_method("my_method", [&obj](*whateverParam*) { obj.templateMethod(*whateverParam*); } );
work?
(assuming obj contains the actual method, but that could be replaced by any instance containing the method).

c++ passing class method as argument to a class method with templates

I'm trying to pass a class method to another class method using template, and cannot find any answer on how to do (no C++11, boost ok):
I simplified the core problem to :
class Numerical_Integrator : public Generic Integrator{
template <class T>
void integrate(void (T::*f)() ){
// f(); //already without calling f() i get error
}
}
class Behavior{
void toto(){};
void evolution(){
Numerical_Integrator my_integrator;
my_integrator->integrate(this->toto};
}
I get as error:
error: no matching function for call to ‘Numerical_Integrator::integrate(<unresolved overloaded function type>)’this->toto);
note: no known conversion for argument 1 from ‘<unresolved overloaded function type>’ to ‘void (Behavior::*)()’
Thank you.
Bonus: What about with arguments ?
class Numerical_Integrator{
template <class T, class Args>
double integrate(void (T::*f)(), double a, Args arg){
f(a, arg);
}
}
class Behavior{
double toto(double a, Foo foo){ return something to do};
void evolution(){
Foo foo;
Numerical_Integrator my_integrator;
my_integrator->integrate(this->toto, 5, foo};
}
Your question is not really about passing a class method as part of a template parameter.
Your question is really about correctly invoking a class method.
The following non-template equivalent will not work either:
class SomeClass {
public:
void method();
};
class Numerical_Integrator : public Generic Integrator{
void integrate(void (SomeClass::*f)() ){
f();
}
}
A class method is not a function, and it cannot be invoked as a function, by itself. A class method requires a class instance to be invoked, something along the lines of:
class Numerical_Integrator : public Generic Integrator{
void integrate(SomeClass *instance, void (SomeClass::*f)() ){
(instance->*f)();
}
}
You need to revise the design of your templates, and/or class hierarchies in order to resolve this first. Once you correctly implement your class method invocation, implementing a template should not be an issue.

Get templated type of Base inside of class that owns instance of Derived

I would like to get the templated type of the base class inside of an object that owns an instance of the derived class. The code snippet below won't work because Base and its ArbitraryType can't be referenced through DerivedString. (line marked with the exclamation point). However, it can most definitely be inferred from the type of its own template (OneOfTheDerivedTypes). In my case, I intend for AnotherObject with a defined template to be inherited from, so I don't want to just hardcode the return type to GetSomethingFromThingy().
// -------------------
// Provided by my API:
// -------------------
template <typename ArbitraryType>
class Base {
virtual void DoSomething(ArbitraryType);
};
template <typename OneOfTheDerivedTypes>
class AnotherObject<OneOfTheDerivedTypes> {
// Other functions that perform useful tasks are here so that
// classes that inherit from AnotherObject need not implement them.
void SomethingMagical();
// A function with a specific return type.
virtual DerivedString::Base::ArbitraryType GetSomethingFromThingy() = 0; /* ! */
protected:
OneOfTheDerivedTypes thingy;
};
// --------------------------------------
// Someone using my API would make these:
// --------------------------------------
class DerivedFloat : public Base<float> {
void DoSomething(float) override;
};
class DerivedString : public Base<string> {
void DoSomething(string) override;
};
class UsefulObject : public AnotherObject<DerivedString> {
// Knows the required return type of GetSomethingFromThingy() without
// needing to specify it as a template. Should throw compile-time error
// if you tried to override with a different return type. In other words,
// forces return type to be string because of use of DerivedString.
string GetSomethingFromThingy() override;
};
One solution to this is specify an additional template arg called ArbitraryType as seen below:
template <typename OneOfTheDerivedTypes, typename ArbitraryType>
class AnotherObject<OneOfTheDerivedTypes> {
virtual ArbitraryType GetSomethingFromThingy() = 0;
protected:
OneOfTheDerivedTypes thingy;
};
class UsefulObject<DerivedString, string> : public AnotherObject<DerivedString, string> {
string GetSomethingFromThingy() override;
};
The programmer then must specify both parameters where OneOfTheDerivedTypes is either DerivedFloat or DerivedString and ArbitraryType is float or string, respectively. Not a good solution because ArbitraryType is completely specified by the choice of OneOfTheDerivedTypes.
I think the extra template (ArbitraryType in AnotherObject) could be avoided by having Base return an instance of ArbitraryType in a public function (call it ReturnInstanceOfArbitraryType()) and use decltype(OneOfTheDerivedTypes::ReturnInstanceOfArbitraryType()) inside of AnotherObject. This seems inelegant because ReturnInstanceOfArbitraryType() is not useful otherwise (and must be public). Is this a case where the proper thing to do is to use a traits class? Is there a better solution? (Still getting the hang of some of this new C++11 stuff). Thanks!
Maybe I've misunderstood your question, but can't you just add a typedef to Base?
template <typename ArbitraryType>
class Base {
virtual void DoSomething(ArbitraryType);
using parameter_type = ArbitraryType;
};
And then you can refer to it:
template <typename OneOfTheDerivedTypes>
class AnotherObject {
// A function with a specific return type.
virtual typename OneOfTheDerivedTypes::parameter_type GetSomethingFromThingy() = 0;
};
And then the override in the derived type will enforce that the return types are the same (or covariant):
class UsefulObject : public AnotherObject<DerivedString> {
string GetSomethingFromThingy() override;
};
You could also add a static_assert if you want a more user-friendly error message:
class UsefulObject : public AnotherObject<DerivedString> {
using base_parameter_type = typename AnotherObject<DerivedString>::parameter_type;
static_assert(std::is_same<string, base_parameter_type>::value,
"mismatched parameter types");
string GetSomethingFromThingy() override;
};
If you can't modify the Base template it's also possible to detect the type using some metaprogramming. First, declare (but don't define) a function that can deduce the type T from Base<T>:
template<typename T> T* detect_base_parameter_type(Base<T>*); // undefined
Now define an alias template which takes one of the derived types as its template parameter, and uses the function above to find the template argument of its base-class:
template<typename DerivedT>
using base_parameter_t = typename std::remove_pointer<
decltype( detect_base_parameter_type(std::declval<DerivedT*>()) )
>::type;
This uses decltype to detect the return type of calling detect_base_parameter_type with a pointer to the derived type. That pointer will convert to a pointer to Base<T> (deducing whatever type T is for DerivedT) and the function's return type will be T*. Then we use remove_pointer to turn that into T.
Now you can use that alias template in your other classes:
template <typename OneOfTheDerivedTypes>
class AnotherObject {
// A function with a specific return type.
virtual base_parameter_t<OneOfTheDerivedTypes> GetSomethingFromThingy() = 0;
};
class UsefulObject : public AnotherObject<DerivedString> {
using base_parameter_type = base_parameter_t<DerivedString>;
static_assert(std::is_same<string, base_parameter_type>::value,
"mismatched parameter types");
string GetSomethingFromThingy() override;
};

C++ - Use Class Name As Function Parameter

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.

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;