I'm working on implementing a reflection mechanism in C++.
All objects within my code are a subclass of Object(my own generic type) that contain a static member datum of type Class.
class Class{
public:
Class(const std::string &n, Object *(*c)());
protected:
std::string name; // Name for subclass
Object *(*create)(); // Pointer to creation function for subclass
};
For any subclass of Object with a static Class member datum, I want to be able to initialize 'create' with a pointer to the constructor of that subclass.
You cannot take the address of a constructor (C++98 Standard 12.1/12 Constructors - "12.1-12 Constructors - "The address of a constructor shall not be taken.")
Your best bet is to have a factory function/method that creates the Object and pass the address of the factory:
class Object;
class Class{
public:
Class(const std::string &n, Object *(*c)()) : name(n), create(c) {};
protected:
std::string name; // Name for subclass
Object *(*create)(); // Pointer to creation function for subclass
};
class Object {};
Object* ObjectFactory()
{
return new Object;
}
int main(int argc, char**argv)
{
Class foo( "myFoo", ObjectFactory);
return 0;
}
I encountered this same problem. My solution was a template function which called the constructor.
template<class T> MyClass* create()
{
return new T;
}
To use this as a function pointer is simple:
MyClass* (*createMyClass)(void) = create<MyClass>;
And to get an instance of MyClass:
MyClass* myClass = createMyClass();
Lambda style:
[](){return new YourClass();}
Using variadic templates you can create a wrapper which will turn the constructor into a functor.
#include <utility>
template <typename T>
struct BindConstructor{
template<typename... Args>
T operator()(Args&&...args)const{
return T(std::forward<Args>(args)...);
}
};
struct Foo {
Foo(int a, int b):a(a),b(b){}
int a;
int b;
};
template <typename Fn>
auto Bar(Fn f){
return f(10,20);
}
int main(){
Foo foo = Bar(BindConstructor<Foo>());
}
https://godbolt.org/z/5W383McTc
Hmm, odd. create is a member variable i.e. only available in class instances but the intent of it seems to be creating an instance in the first place.
You cannot take the address of a constructor, but you can create static factory methods of your own and take the address of that.
You can't use regular function pointers on methods, you have to use method pointers, which have bizarre syntax:
void (MyClass::*method_ptr)(int x, int y);
method_ptr = &MyClass::MyMethod;
This gives you a method pointer to MyClass's method - MyMethod. However this isn't a true pointer in that it's not an absolute memory address, it's basically an offset (more complicated than that due to virtual inheritance, but that stuff is implementation specific) into a class. So to use the method pointer, you have to supply it with a class, like this:
MyClass myclass;
myclass.*method_ptr(x, y);
or
MyClass *myclass = new MyClass;
myclass->*method_ptr(x, y);
Of course it should be obvious at this point that you can't use a method pointer to point to an objects constructor. In order to use a method pointer you need to have an instance of the class so it's constructor has already been called! So in your case Michael's Object Factory suggestion is probably the best way of doing it.
Using Qt, you can call a constructor with Qt reflection mechanisms (QMetaObject) if you declare the constructor as Q_INVOKABLE (nothing more to do than that).
class MyClass : public QObject {
Q_OBJECT
public:
Q_INVOKABLE MyClass(int foo);
MyClass *cloningMySelf() {
return metaObject()->newInstance(Q_ARG(int, 42));
}
};
I'm not sure you will want to embed Qt just for that feature ;-) but maybe you would like to have a look on the way it does that.
http://doc.qt.io/qt-5/metaobjects.html#meta-object-system
If you want an actual function pointer representing the constructor, not a functor or closure, you can create a universal factory template:
#include <iostream>
namespace {
template <typename Type, typename... Args>
Type create(Args... args)
{
return Type{std::forward<Args>(args)...};
}
}
template <typename Type, typename... Args>
static constexpr auto constructor = &create<Type, Args...>;
struct Foo {
Foo(double v){ std::cout << "Foo ctor " << v << std::endl; }
};
int main()
{
auto z = constructor<Foo, double>(0.33);
return 0;
}
Foo ctor 0.33
https://godbolt.org/z/qKGGGzjTs
This is similar to Michael Burr's answer, except that you don't have a static factory method per object and it allows any kind of constructor (not just default)
This is similar to bradgonesurfing's answer, except that you create one function pointer per constructor and not one functor per class representing all constructors for that class.
Even though this question is old and already has several very helpful answers, I am adding this additional suggestion because having one function pointer for every constructor of any class is useful when implementing a runtime type reflection system.
Related
Is there a way to call the constructor of a class, given the pointer-type of that class type as the template parameter?
MyClass<AnotherClass*> => how to call the default constructor of AnotherClass in MyClass?
This one does obviously not work (doesnt compile), because in GetNew the new T and the return type T don't fit together. What would be needed is some kind of "type dereferencing" to come to the class type, given the pointer type.
class AnotherClass
{};
template <class T>
class MyClass
{
public:
// this does obviously not compile
virtual T GetNew()
{
return new T; // how let T be AnotherClass* and to create an AnotherClass instance here?
}
};
int main()
{
// this does not compile:
MyClass<AnotherClass*> tmp; // here, AnotherClass is **pointer** type
AnotherClass* a = tmp.GetNew();
}
A workaround would be to use the class type as the template parameter and use poiter types as return types. But this changes the interface, so I would still like a solution to pointer template type.
class AnotherClass
{};
template <class T>
class MyClass2
{
public:
virtual T* GetNew()
{
return new T;
}
};
int main()
{
// this does work:
MyClass2<AnotherClass> tmp2; // here, AnotherClass is **not** pointer type
AnotherClass* b = tmp2.GetNew();
}
Another workaround could be to use a factory or similar, but I would like to use the default constructor without additional helping structures.
You can use std::remove_pointer to get the type pointed to.
Provides the member typedef type which is the type pointed to by T, or, if T is not a pointer, then type is the same as T.
E.g.
virtual T GetNew()
{
return new std::remove_pointer_t<T>;
}
If you require the parameter to MyClass to be a pointer, you can specialise it for pointers and leave it undefined for other types
template<typename>
class MyClass;
template<typename T>
class MyClass<T*>
{
public:
virtual T* GetNew()
{
return new T;
}
};
int main()
{
// MyClass2<AnotherClass> tmp1; // compile error
MyClass2<AnotherClass *> tmp2; // fine
AnotherClass* b = tmp2.GetNew(); // GetNew returns the exact type parameter
}
I have a class called classA, something like this:
class classA {
private:
char* data;
public:
classA(const classA&) = delete;
~classA();
};
~classA()
{
delete[] data;
}
In another class, let's call it classB, I have as a member a shared pointer to classA:
class classB
{
private:
std::shared_ptr<classA> ptrA;
public:
classB(std::shared_ptr<classA>);
};
classB(std::shared_ptr<classA> sp) : ptrA(sp)
{}
This is how I instantiate my classB:
classA ca;
classB cb(std::make_shared<classA>(ca));
This gives me the following error:
attempting to reference a deleted function
Obviously, I am trying to reference the copy constructor, which I defined as deleted (there is a reason for this, objects of this class shouldn't be copied). But I am confused as to why the copy constructor is called since I am passing a shared pointer, and how to avoid this.
You're calling the copy constructor trying to make the shared pointer.
std::make_shared<classA>(ca)
^^ constructs the classA using these parameters
You can call make_shared<classA>() to create a shared pointer to a default constructed classA. Or chose another constructor.
This example can be simplified quite a bit.
#include <memory>
class classA {
public:
classA(const classA&) = delete;
classA() = default;
};
int main() {
classA ca; // note, no ()
auto sp = std::make_shared<classA>(ca); // problem.
auto sp2 = std::make_shared<classA>(); // this does what you want
}
You are passing ca as an argument to std::make_shared, which constructs a classA by calling classA::classA with whatever arguments that you passed to make_shared.
This might be more obvious if you consider how a make_shared might be implemented.
template <typename Cls, typename... Args>
std::shared_ptr<Cls> MakeShared(Args&&... args) {
//this is where the copying happens
return std::shared_ptr<Cls>{new Cls{std::forward<Args>(args)...}};
}
int main() {
classA ca;
auto sp = MakeShared<classA>(ca);
auto sp2 = MakeShared<classA>();
}
You pass ca to MakeShared, which then calls new Cls(...) where the ... is whatever you passed to MakeShared, in this case, another classA object.
If the above is too dense (maybe you aren't used to forward or variadic templates), then consider this simplified version of MakeShared which does the same thing for your problem case
template <typename Cls, typename Arg>
std::shared_ptr<Cls> MakeShared(const Arg& arg) {
// copy here ----+
// v
return std::shared_ptr<Cls>{new Cls{arg}};
}
int main() {
classA ca;
auto sp = MakeShared<classA>(ca);
}
I am trying to achieve that certain objects within my application can only be constructed as shared_ptr's by a call to a static method called "create".
Of course I could do this by directly adding the static 'create' method to all the respective class. However, this would mean I have to repeat very similar code in almost all my classes. A macro would work, but I do not find this very elegant.
I came up with an alternative way of doing this by deriving all classes from a templated 'BaseObject' class that implements the 'create' method and returns the pointer. This almost works, except that std::make_shared cannot access the constructor of its child class when it is protected.
The non-solution would be to make the child class constructor public (see (1) in the example below). But now Foo can be normally constructed again and this would defeat the entire point. An alternative solution would be to friend BaseObject in the child class and make use of shared_ptr directly (see (2) in the example).
Both solutions put extra burden on the implementer of the child class. Since they have to either find an alternative way of making the constructor non-public or put a friend declaration. The (2) solution has the additional problem of not being able to use the more efficient make_shared.
My question: is there a better way of doing this?
template<class T>
class BaseObject
{
public:
typedef std::shared_ptr<T> SharedPtr;
template<class... Args>
static typename BaseObject<T>::SharedPtr create(Args&&... args)
{
return std::make_shared<T>(args...);
//return std::shared_ptr<T>(new T(args...)); (2)
}
};
class Foo : public BaseObject<Foo>
{
//friend BaseObject<Foo>; (2)
protected: //public (1)
Foo(int a = 0) : m_foo(a) {}
private:
int m_foo;
};
int main(int argc, char* argv[])
{
Foo::SharedPtr bla = Foo::create(1);
return 0;
}
Update:
They pass-key idiom seems to provide the best solution for me at this moment:
template<class T>
class BaseObject
{
public:
typedef std::shared_ptr<T> SharedPtr;
class Key
{
friend class BaseObject<T>;
Key() {}
};
template<class... Args>
static typename BaseObject<T>::SharedPtr create(Args&&... args)
{
return std::make_shared<T>(Key(), args...);
}
};
class Foo : public BaseObject<Foo>
{
public:
Foo(BaseObject<Foo>::Key, int a = 0) : m_foo(a) {}
private:
int m_foo;
};
The good things:
Only possible to create an object of Foo as a shared_ptr through
Foo::create.
No need to add complex friend declarations in Foo.
std::make_shared still works.
The only problem with this solution is the requirement to have 'Key' as a first argument in the constructor. But I can live with that.
Better is subjective, but I believe it would be a little more intuitive if you would make your constructor private, and std::make_shared a friend function. This way the only function that could create your object would be std::make_shared, and you could write
std::shared_ptr<Foo> ptr = std::make_shared<Foo>(12);
instead of:
Foo::SharedPtr bla = Foo::create(1);
So any future reader of your code would understand what you mean withou actually looking at the Foo class.
UPDATE
I have tried out what I wrote, but did not really work. Here is an answer for a similar question instead, which most likely also aplies for your question:
Using make_shared with a protected constructor + abstract interface
UPDATE 2
Here is how you can make it work (VC++2013)
#include <memory>
using namespace std;
class Foo
{
protected:
Foo(int a = 0) : m_foo(a) {}
private:
int m_foo;
friend shared_ptr<Foo> make_shared<>();
friend class _Ref_count_obj<Foo>;
};
int main()
{
shared_ptr<Foo> foo = make_shared<Foo, int>(12);
return 0;
}
_Ref_count_obj is internally used by make_shared, that's why you need to befriend that too.
I would like to encapsulate the assignment of functors to a std::function into a method. Instead of passing a std::function or a pointer to a std::function I have to pass functors that inherit from a common abstract class Slot (i.e. these slots provide additional functionality).
I stumbled upon this problem in a different shape here. E.g. there, the motivation of using pointers of generic slots instead of std:functions is lifetime management of the functors.
The following code illustrates the problem. See the assignFunctorPtr(...) method.
#include <iostream>
#include <functional>
template<class FunSig>
class Slot;
template<class R>
class Slot<R()>
{
public:
typedef R Ret_type;
public:
virtual ~Slot() {}
virtual Ret_type operator()() = 0;
};
template<class R, class A1>
class Slot<R(A1)>
{
public:
typedef R Ret_type;
typedef A1 Arg1_type;
public:
virtual ~Slot() {}
virtual Ret_type operator()(Arg1_type) = 0;
};
class TestSlot: public Slot<void (float &)>
{
public:
void operator()(float& f)
{ std::cout << f ;}
};
template<class FunSig>
class TestSignal
{
public:
typedef Slot<FunSig> Slot_type;
std::function<FunSig> f;
void assignFunctorPtr(Slot_type* slot_ptr)
{
//f = std::ref(*slot_ptr); // A -> works!
f = *slot_ptr; // B -> compiler error!
}
};
int main()
{
TestSlot* slot = new TestSlot;
TestSignal<void (float &)>* signal = new TestSignal<void (float &)>;
signal->assignFunctorPtr(slot);
}
This code breaks if version B is used in assignFunctorPtr(...).
Error: "error: cannot allocate an object of abstract type ‘Slot<void(float&)>’
note: because the following virtual functions are pure within ‘Slot<void(float&)>’"
And it compiles if version A in assignFunctorPtr(...) is used.
Why does it compile if std::ref is used to wrap the functor?
Hence what are the specific requirements of std::function for a functor (see also std::function reference)
What would be the correct/best way to solve this problem?
Is it save to use std::ref?
std::function copies its arguments. Since the object you want to assign is of the base type (and has a pure virtual member function), it cannot be copied. Note that, if it didn't have a pure virtual member function, it might be copyable, but you would suffer from object slicing.
Using std::ref is safe as long as you make sure that the object to which std::ref is bound lives longer that all references to it.
The most elegant solution, in my opinion, would be to make assignFunctorPtr a function-template that takes an argument of the real type of functor (as opposed to a base-type). If this is copyable, the assignment would work without std::ref.
template<class SlotType>
void assignFunctorPtr(SlotType* slot_ptr)
{
f = *slot_ptr; // works if SlotType is copyable
}
I believe this version would also work if SlotType was just movable, but I might be wrong there.
I'm working on implementing a reflection mechanism in C++.
All objects within my code are a subclass of Object(my own generic type) that contain a static member datum of type Class.
class Class{
public:
Class(const std::string &n, Object *(*c)());
protected:
std::string name; // Name for subclass
Object *(*create)(); // Pointer to creation function for subclass
};
For any subclass of Object with a static Class member datum, I want to be able to initialize 'create' with a pointer to the constructor of that subclass.
You cannot take the address of a constructor (C++98 Standard 12.1/12 Constructors - "12.1-12 Constructors - "The address of a constructor shall not be taken.")
Your best bet is to have a factory function/method that creates the Object and pass the address of the factory:
class Object;
class Class{
public:
Class(const std::string &n, Object *(*c)()) : name(n), create(c) {};
protected:
std::string name; // Name for subclass
Object *(*create)(); // Pointer to creation function for subclass
};
class Object {};
Object* ObjectFactory()
{
return new Object;
}
int main(int argc, char**argv)
{
Class foo( "myFoo", ObjectFactory);
return 0;
}
I encountered this same problem. My solution was a template function which called the constructor.
template<class T> MyClass* create()
{
return new T;
}
To use this as a function pointer is simple:
MyClass* (*createMyClass)(void) = create<MyClass>;
And to get an instance of MyClass:
MyClass* myClass = createMyClass();
Lambda style:
[](){return new YourClass();}
Using variadic templates you can create a wrapper which will turn the constructor into a functor.
#include <utility>
template <typename T>
struct BindConstructor{
template<typename... Args>
T operator()(Args&&...args)const{
return T(std::forward<Args>(args)...);
}
};
struct Foo {
Foo(int a, int b):a(a),b(b){}
int a;
int b;
};
template <typename Fn>
auto Bar(Fn f){
return f(10,20);
}
int main(){
Foo foo = Bar(BindConstructor<Foo>());
}
https://godbolt.org/z/5W383McTc
Hmm, odd. create is a member variable i.e. only available in class instances but the intent of it seems to be creating an instance in the first place.
You cannot take the address of a constructor, but you can create static factory methods of your own and take the address of that.
You can't use regular function pointers on methods, you have to use method pointers, which have bizarre syntax:
void (MyClass::*method_ptr)(int x, int y);
method_ptr = &MyClass::MyMethod;
This gives you a method pointer to MyClass's method - MyMethod. However this isn't a true pointer in that it's not an absolute memory address, it's basically an offset (more complicated than that due to virtual inheritance, but that stuff is implementation specific) into a class. So to use the method pointer, you have to supply it with a class, like this:
MyClass myclass;
myclass.*method_ptr(x, y);
or
MyClass *myclass = new MyClass;
myclass->*method_ptr(x, y);
Of course it should be obvious at this point that you can't use a method pointer to point to an objects constructor. In order to use a method pointer you need to have an instance of the class so it's constructor has already been called! So in your case Michael's Object Factory suggestion is probably the best way of doing it.
Using Qt, you can call a constructor with Qt reflection mechanisms (QMetaObject) if you declare the constructor as Q_INVOKABLE (nothing more to do than that).
class MyClass : public QObject {
Q_OBJECT
public:
Q_INVOKABLE MyClass(int foo);
MyClass *cloningMySelf() {
return metaObject()->newInstance(Q_ARG(int, 42));
}
};
I'm not sure you will want to embed Qt just for that feature ;-) but maybe you would like to have a look on the way it does that.
http://doc.qt.io/qt-5/metaobjects.html#meta-object-system
If you want an actual function pointer representing the constructor, not a functor or closure, you can create a universal factory template:
#include <iostream>
namespace {
template <typename Type, typename... Args>
Type create(Args... args)
{
return Type{std::forward<Args>(args)...};
}
}
template <typename Type, typename... Args>
static constexpr auto constructor = &create<Type, Args...>;
struct Foo {
Foo(double v){ std::cout << "Foo ctor " << v << std::endl; }
};
int main()
{
auto z = constructor<Foo, double>(0.33);
return 0;
}
Foo ctor 0.33
https://godbolt.org/z/qKGGGzjTs
This is similar to Michael Burr's answer, except that you don't have a static factory method per object and it allows any kind of constructor (not just default)
This is similar to bradgonesurfing's answer, except that you create one function pointer per constructor and not one functor per class representing all constructors for that class.
Even though this question is old and already has several very helpful answers, I am adding this additional suggestion because having one function pointer for every constructor of any class is useful when implementing a runtime type reflection system.