I want to use a static member in a template class to instantiate a singleton object for each class that inherits from that template class.
Here is an example:
#include <iostream>
#include <vector>
struct X{
static std::vector<X*>& getRegistry(){
static std::vector<X*> registry;
return registry;
}
X(){
getRegistry().push_back(this); // Each X adds itself to the registry
}
};
template<typename T>
struct Y : X{
private:
static T instance; // The per-type singleton
};
template<typename T>
T Y<T>::instance {};
The idea is that objects of type X enter themselves into a "registry" whenever they are created. Class Y<T> that is derived from X is a template class that should instantiate a static singleton object of each type that inherits from it (using the curiously recurring template pattern).
The idea is that the "registry" will contain one object of each class that inherits from Y<T>. These classes should not have to do anything to get added to the registry; instead, simply inheriting from Y<T> should be enough to create a singleton object that is added to the registry.
I tried my code like this:
struct A : Y<A>{};
struct B : Y<B>{};
struct C : Y<C>{};
int main(){
std::cout << "Number of objects in the registry: " << X::getRegistry().size() << std::endl;
// Should print "3"
}
Fiddle link: http://ideone.com/aWDEg4
The desired behaviour should be that one A, one B, and one C, should be in the registry. But none of them is. The problem is that Y<T>::instance is not instantiated for any of the classes as it is not used in the code. However, I never want to use these fields, they are just their to instantiate the singleton. So is there a way to force the instantiation of the static field without having to add additional code to the deriving classes (i.e., A,B, and C)?
I know I can explicitly instantiate template class Y<A>;, but this would add additional code to the deriving class A.
You could just create static instances:
struct A : Y<A>{};
struct B : Y<B>{};
struct C : Y<C>{};
static A a;
static B b;
static C c;
int main(){
std::cout << "Number of objects in the registry: " << X::getRegistry().size() << std::endl;
}
output:
Number of objects in the registry: 3
I don't think you can avoid involving the clients of Y, but you can make Y's constructor private forcing client involvement. For example, this works as you want:
template<typename T>
struct Y : X {
Y(const Y<T> &other) {}
static Y<T> create() { &instance; return Y<T>(); }
private:
static T instance; // The per-type singleton
Y() {}
};
template<typename T>
T Y<T>::instance {};
struct A : Y<A> { A() : Y(Y::create()) {} };
struct B : Y<B> { B() : Y(Y::create()) {} };
struct C : Y<C> { C() : Y(Y::create()) {} };
The client involvement is the invocation of Y::create which also happens to force the instantiation of the instance member. Granted, this is probably not what you wanted, but it does work. Note also, my previous comment about the this pointer will still apply even if you can add the static instances to your registry.
Related
I have some third-party abstract base class
struct foo
{
virtual foo*job() = 0;
...
static void* make_space(size_t sizeofDerived);
};
which I cannot alter. Objects of type foo (and all derived classes) must only be created/constructed using placement-new into the memory returned by foo::make_space(),
because ordinary construction, as in
derived_from_foo z; // or
auto p = new derived_from_foo();
may cause undesired problems (corrupting memory, depending on the compiler, as I found out eventually). So my question: how can I write/design a derived class
struct bar // still abstract, since foo::job() is not provided
: foo
{
...
template<typename Derived, typename...Args>
static Derived* create(Args&&...args)
{
return ::new(foo::make_space(sizeof(Derived)))
Derived(std::forward<Args>(args)...);
}
};
such that construction of objects of type bar or any type derived from bar by any other means than through bar::create() fails at (i) compilation or (ii, less ideal) at run-time?
You can in fact enforce it, at a price.
Consider this class:
class A
{
public:
class Tag
{
public:
Tag(const Tag&) = default;
Tag(Tag&&) = default;
private:
Tag() {}
friend class A;
};
A(Tag, int a, char b) : a(a), b(b) {}
int a;
char b;
template<typename T, typename ... Params>
static T* make(Params&& ... params)
{
return new T(Tag(), std::forward<Params>(params)...);
}
};
Its constructor requires a Tag parameter, but you cannot make a Tag, it's got a private constructor. You can derive from A, but you cannot directly create objects of a derived class either: it needs to pass a Tag to its parent constructor, and you cannot make one.
So the only way to create an object of A or a derived class is by calling A::make.
Well there is still a way to cheat
class B : public A
{
public:
B(Tag t, double q) : A(t, 42, 'z'), q(q) {
// cheating:
B* other = new B(t, 3.14);
}
double q;
};
If this bothers you, you still can enforce correctness at run-time by making Tag non-reusable à la std::unique_ptr. Remove the copy ctor, throw in a private bool flag that you set on construction and clear on move-out, and check it inside make.
Is it possible, to somehow allow parent to access child protected members?
template <class T>
class B {
public :
void print()
{
cout << T::a << T::b << endl;
}
};
class C : public B<C>
{
protected :
static int a;
static int b;
public :
C() {
print();
}
};
This will be useful for me to inherit multiple objects without polymorphism(virtual). Any suggestgions??
Edit:
I find two solutions as suggested below ::
make the B as a friend class,
CRTP
Few more points to consider, while using CRTP make sure you use inline other wise it won't make it any faster(but code bloat may happen). Do not forget to make the B constructor protected(in case of static derived data access).
CRTP can also be used to not transfer static constant data(virtual static const) from base class to derived
The modern compilers use a concept called devirtualization i think it is in most compilers now.
This will be useful for me to inherit multiple objects without polymorphism(virtual).
It's a well known pattern and aka named static polymorphism.
The CRTP uses static_cast<T*>(this) to reference the derived class functions usually:
template <class T>
class B {
public :
void print()
{
cout << static_cast<T*>(this)->a << static_cast<T*>(this)->b << endl;
// ^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^
}
};
I need to somehow allow parent to access child protected data, is it possible?
Of course it is possible. These need to be public members of T, or you need to make B<T> a friend class of T:
class C : public B<C>
{
friend class B<C>;
// ^^^^^^^^^^^^^^^^^^
protected :
static int a;
static int b;
public :
C() {
print();
}
};
Live Demo
The friend declaration still preserves the encapsulation of class C, while opening access to a specific interface declared in class B<T>.
Given a base class Base that has two derived classes, DerA and DerB, can the derived classes have a member variable that is used in a Base member function, but is a different type for each class?
class Base {
* a // Declare a as *something*, so it can be used by "doWork"
template <typedef T>
void doWork(T b) { // Add another value to "a" which is of its same type
a += b; // For example; an operation that works on "a", no matter what numeric type it is
}
}
class DerA : public Base {
// Make "a" an int
}
class DerB : public Base {
// Make "a" a float
}
In practice, a will be a base struct, while DerA and DerB will have derived versions of the base struct (derivative classes will each have a derived form of the struct specific to their purpose, but each must do a simple operation on a, so it seems pointless to copy/paste that simple function for each derivative when I can just use a template function). I would just type a as the base struct type, but then I lose access to the various specialized member functions and variables that each derived struct has (if I understand inheritance correctly).
I apologize if this question is a repeat, but I don't know what this quality would be called, so Googling proved fruitless.
What you might want is the CRTP.
template<class D>
struct Base {
D* self() { return static_cast<D*>(this); }
D const* self() const { return static_cast<D*>(this); }
template<class T>
void doWork(T b) {
self()->a += b;
}
};
struct DerA : public Base<DerA> {
int a;
};
struct DerB : public Base<DerB> {
double a;
};
Here we pass the derived type to our base class. Within the base class, you can use self()-> to access fields in the derived type. This allows basically full access to the derived type, while letting us share code in the base class.
Note that you cannot pass DerA and DerB around as a Base this way. If you want that, you need a virtual method doWork, and virtual template methods don't exist.
CRTP stands for the curiously repeating template pattern, which I imagine is named because it is strange, it involves repeating a type, and it keeps on showing up in strange corners as being useful.
Type erasure probably won't work either, as you want to dispatch the type erasure from two different spots in the code base (the double dispatch problem: you need a centralized list of types supported to do the type Cartesian product on).
To expand on that, in order to support a+=b where both a and b are arbitrary types, you would have to expand over all types twice over, including types that are never mutually visible at the same spot in a compilation unit. That isn't possible.
If you need a common base, and there are only some types you pass to doWork, here is how you do it:
struct Base {
virtual void doWork( double ) = 0;
virtual void doWork( int ) = 0;
virtual void doWork( long long ) = 0;
};
template<class D>
struct Base_helper:Base {
D* self() { return static_cast<D*>(this); }
D const* self() const { return static_cast<D*>(this); }
template<class T>
void doWork_impl(T b) {
self()->a += b;
}
void doWork( double x ) override { doWork_impl(x); };
void doWork( int x ) override { doWork_impl(x); };
void doWork( long long x ) override { doWork_impl(x); };
};
struct DerA : public Base_helper<DerA> {
int a;
};
struct DerB : public Base_helper<DerB> {
double a;
};
note that every version of doWork must be valid to call on each of the Ders, as the Base_helper instantiates all of them.
If the kind of type passed to doWork is unbounded, yet the types of Der is bounded, you can do something like the above only backwards. It gets awkward, however. Your best bet in that kind of situation is to use a boost::variant type solution.
I guess you want to achieve something like this:
template<typedef T>
class Base {
T a;
void doWork(T b) { // Add another value to "a" which is of its same type
a += b; // For example; an operation that works on "a", no matter what numeric type it is
}
}
class DerA : public Base<int> {
}
class DerB : public Base<float> {
}
Or you can dump classes DerA and DerB entirely and use typedefs instead:
typedef Base<int> DerA;
typedef Base<float> DerB;
This can be easily solved with a CRTP-like pattern:
template<class D> // Base class is templated
class Base {
public:
D a;
void doWork(D b) {
a += b;
}
};
class DerA : public Base<int> {};
class DerB : public Base<float> {};
Live Example
Edit: in case you need only one common base (Base<int> is a completely different type from Base<float>) you might use an interface class and have Base inherit from it.
This question already has answers here:
Is Template of derived object a subclass of template of base type
(5 answers)
Closed 8 years ago.
I have a template class that replaces direct construction of objects with just storing them for future purpose.
template<typename T>
typedef struct Construction{
int arg;
} Construction;
Now I want to pass a std::vector< Construction< Base > > to a function that should then call the constructors of every Element with the given argument.
This works when I only use the base type, but as soon as I try to mix base and derived types, problems emerge:
Construction<Base> construct = Construction<Derived>(5);
This won't work, while a regular assignment like Base& b = Derived(5); does.
Why does this not work?
This sounds like a lazy factory pattern. As you say in a comment, Constr<Base> does not hold enough information to construct a Derived. So when storing in a vector, you should use pointers rather than values. If you are willing to use the free store for the final objects, one solution is the following:
struct Base { int x; };
struct Derived : public Base { Derived(int x) : Base{x} { } };
template<typename T>
struct Constr;
template<>
struct Constr<Base> {
virtual std::unique_ptr<Base> make() const = 0;
};
template<typename T>
struct Constr : Constr<Base> {
int arg;
Constr(int arg) : arg{arg} { }
std::unique_ptr<Base> make() const override
{
return std::make_unique<T>(arg);
}
};
int main() {
Constr<Derived> a{5}, b{2}, c{8};
std::vector<Constr<Base>*> v{&a, &b, &c};
// later...
std::vector<std::unique_ptr<Base>> u;
for (auto& i : v)
u.push_back(i->make());
for (auto& i : u)
std::cout << i->x << " "; // 5 2 8
}
For this to work, we now make Constr<Derived> derive Constr<Base>. So we can use pointers/references to such objects following the same rules as pointers/references to Base/Derived, without defining any special constructors.
Note the forward declaration of Constr: this is needed because specialization Const<Base> needs to be defined before the general template; in turn, this is needed because the latter implicitly instantiates the former (by deriving it).
I cannot think of a simple solution without the free store, though. The only possibility is to use a raw memory buffer, either as a data member of Constr<Base>, or passed as an argument to make(). But this needs some work and will always have an upper bound on the size of Derived. Or, we could automatically choose between stack/free store depending on object size; this is generic but needs even more work.
It does not work, because instantiations of class templates are not related via a subclass-superclass relationship, even if the types, used in the instantiation are.
In many cases you can solve the problem, by providing a constructor template and/or assignment operator template to your original template, like:
struct Base {
int x;
};
struct Derived : public Base {
int y;
};
template<typename T>
struct Constr {
T t;
Constr() = default;
template<typename U> Constr(const Constr<U> &a) : t(a.t) {}
};
int main() {
Constr<Derived> a;
Constr<Base> b = a;
// Constr<Derived> c = b; // error, as it should
}
We have a special framework for interfaces in our project, and part of the requirements is that classes which represent an interface may only be used as virtual base classes, not as non-virtual ones. Is there a way to enforce this in code? That is, produce a compilation error if the class is derived from non-virtually.
I have access to C++11 as implemented by VS 2010: this means static_assert, enable_if and <type_traits> are available.
IMO, there is no clean and platform independent solution available to this problem.
The best way is to manually go and change each and every inheritance to virtual inheritance.
To accomplish that, identifying the derived classes of your interface (say class Base) is easy(!). Below steps can be followed for that:
Make class Base as final (c++11); i.e. class Base final { ...
Compile the code, it will generate compiler error for all its
derived classes
Go and check every derived class and make the inheritance as
virtual
Remove the final keyword and compile the code successfully
This process (unfortunately) has to be followed periodically, whenever you want to do such sanity checking.
This is possible to check at compile time. The key is that, if we have a diamond pattern:
You can unambiguously cast D& to A&. However, if the inheritance is non-virtual:
the cast would ambiguous. So let's try to make a diamond!
template <typename Base, typename Derived>
class make_diamond {
struct D2 : virtual Base { }; // this one MUST be virtual
// otherwise we'd NEVER have a diamond
public:
struct type : Derived, D2 { };
};
At which point it's just another void_t-style type trait:
template <typename Base, typename Derived, typename = void>
struct is_virtual_base_of : std::false_type { };
template <typename Base, typename Derived>
struct is_virtual_base_of<Base, Derived, void_t<
decltype(static_cast<Base&>(
std::declval<typename make_diamond<Base, Derived>::type&>()))
>> : std::true_type { };
If the cast is unambiguous, the expression in the partial specialization will be valid, and that specialization will be preferred. If the cast is ambiguous, we'll have a substitution failure, and end up with the primary. Note that Base here doesn't actually need to have any virtual member functions:
struct A { };
struct B : public A { };
struct C : virtual A { };
std::cout << is_virtual_base_of<A, B>::value << std::endl; // 0
std::cout << is_virtual_base_of<A, C>::value << std::endl; // 1
And if it has any pure virtual member functions, we don't have to override them since we're never actually constructing an object.
struct A2 { virtual void foo() = 0; };
struct B2 : public A2 { void foo() override { } };
struct C2 : virtual A2 { void foo() override { } };
std::cout << is_virtual_base_of<A2, B2>::value << std::endl; // 0
std::cout << is_virtual_base_of<A2, C2>::value << std::endl; // 1
Of course if your class is marked final, this won't work at all. But then, if it were final, it wouldn't matter what kind of inheritance it had anyway.
Interesting problem. You may be able to get close to what you want by hiding the interface class and exposing a concrete class that inherits from the interface virtually. This obviously entails some workarounds and awkwardness, but it might be adaptable to your needs. Here's an example:
#include <iostream>
using namespace std;
class Hide {
struct VInterface {
void foo() const { cout << "VInterface::foo()\n"; }
VInterface const &as_interface() const { return *this; }
protected:
virtual ~VInterface() { }
};
public:
struct VBase : virtual VInterface {
};
};
typedef Hide::VBase VBase;
struct VDiamond1 : VBase { };
struct VDiamond2 : VBase { };
struct VConcrete : VDiamond1, VDiamond2 { };
int main() {
VConcrete vc;
auto const &vi = vc.as_interface();
vi.foo();
}
It may be possible to reconstruct a name using decltype() and as_interface() that may be usable for inheritance, but the ones I tried resulted in compiler errors that the destructor was protected, so I expect that if it is possible, it's at least relatively difficult and might be sufficient for your needs.