I have two classes using the Curiously Reoccurring Template Pattern with a parent class.
When I compile on VS2013 I get two errors, one for each subclass, stating:
'Parent<Child1>::_child' uses undefined struct 'Child1'
'Parent<Child2>::_child' uses undefined struct 'Child2'
Am I including the files incorrectly, or do I need to make some sort of forward declaration?
Child1.h
#include "Parent.h"
struct Child1 : public Parent<Child1>
{
void init()
{
sharedCode();
}
};
Child2.h
#include "Parent.h"
struct Child2 : public Parent<Child2>
{
void init()
{
sharedCode();
}
};
Parent.h
template<class CHILD>
struct Parent
{
void sharedCode()
{
}
CHILD _child;
};
main.cpp
#include "Child1.h"
#include "Child2.h"
int main()
{
Child1 c1;
Child2 c2;
}
When using the recurring template pattern, the child is an incomplete type in the scope of the parent.
template<class CHILD>
struct Parent
{
CHILD _child; // <- there, incomplete
};
You cannot instantiate an incomplete type as its definition is not there yet.
So... why is that?
A type become complete when the compiler encounter the closing bracket:
struct Hello {
// Technically not complete yet
};
// Complete here, we encountered the closing bracket.
Also, parent classes are required to be complete type themselves:
struct Incomplete;
struct NiceTry : Incomplete {}; // ERROR! `Incomplete` is an incomplete type.
So we have two rules here: the parent of a class must be complete, and a type is not complete until the closing bracket. Inside the parent of a CRTP, we fail both condition: The parent is evaluated before the class scope (they are also positionned before the class scope in the code) and since the parent of a class must be complete, it must be complete before the child class is. You cannot have mutually complete types in class scope, no matter how hard you try:
struct class2;
struct class1 {
// Class 2 is incomplete here
};
struct class2 {
// class1 complete
};
You cannot have both complete at the same time in both scopes.
The same thing happens with CRTP, there is no exceptions there.
Also, your code is roughly equivalent to this:
struct class1 {
class2 instance;
};
struct class2 {
class1 instance;
};
If you try to compute the size of the types, you run into an infinite recursion. You cannot have a type that contain itself.
To fix your problem, don't try to contain the child. Instead, since you know 100% which class is the child, simply cast this:
template<typename Child>
struct parent {
void common_behavior() {
child().function1();
std::cout << child().member1 + child().member2;
}
private:
auto child() noexcept -> Child& { return *static_cast<Child*>(this); }
auto child() const noexcept -> Child const& { return *static_cast<Child const*>(this); }
};
And implement the child like that:
struct child1 : parent<child1> {
void function1() { std::cout << "This is child 1"; }
int member1, member2;
};
struct child2 : parent<child2> {
void function1() { std::cout << "This is child 2"; }
float member1, member2;
};
Live example
Related
In any case, A::Stuff is protected, so why inheriting from A and forcing its members' accessibility to protected resulting in an error ?
class A {
protected:
template <typename T>
static void Stuff() {
T::template Stuff<T>();
}
};
class B : protected A {
public:
void something() { A::Stuff<B>(); }
// I have these two, inelegant workarounds:
// using A::Stuff; // KO: This is wrong, it changes the accessibility of Stuff.
// class B : public A // KO: Accessibility changed.
// friend A; // OK: This seems fine.
};
int main() {
B b;
b.something();
}
Code available at: https://godbolt.org/z/r1Ya3rzsK
Assuming the classes A and B as defined above clang and gcc will give you something like that:
'Stuff' is a protected member of 'A'
T::template Stuff<T>();
I give a workaround in the comment and more are welcome as long as the members' accessibility is not changed.
The problem is that the A::Stuff<B>() will call T::Stuff<T>() with T=B aka B::Stuff<B>(). B doesn't have a Stuff function, so it will try falling back to A::Stuff which is invalid, as you made the inheritance protected. (btw if it was valid, because the inheritance was public that would lead to an infinite recursion).
I think you don't want an infinite recursion here. If you want Stuff<B> to be valid add a Stuff function to B.
#include <iostream>
class A {
protected:
template <typename T>
static void Stuff() {
std::cout<<"called A\n";
T::template Stuff<T>();
}
};
class B : protected A {
public:
void something() { A::Stuff<B>(); }
template <typename T>
static void Stuff() {
std::cout<<"called B\n";
//...
}
// I have these two, inelegant workarounds:
// using A::Stuff; // KO: This is wrong, it changes the visibility of Stuff.
// class B : public A // KO: Visibility changed.
// friend A; // OK: This seems fine.
};
int main() {
B b;
b.something();
}
I am having difficulty understanding the piece of code given below.
class Child1 : public Base1 {
public:
int Func1(char *Var);
}
class Cls_X: public std::enable_shared_from_this<Cls_X> {
public:
void Func2(char *Var_copy);
}
Func2 is called from Func1 as below
int Func1(char * Var){
...
make_shared<Cls_X>(ioc, ctx)->Func2(Varcopy_ptr);
...
}
Questions:
How class Cls_X: public std::enable_shared_from_this<Cls_X> works?
Tried googling but couldn't understand the documentation for this, Can someone explain in simple english?
Are Cls_X and Child1 both derived class of Base1 here?
NOTE:
The tag [boost] is added because the code example is taken from one of the boost libraries. Please check the example to see how shared_from_this is used in the program
Ps 1:- Change the suitable title if possible.
How class Cls_X: public std::enable_shared_from_this<Cls_X> works?
It can work iff the specialization of the template class (here std::enable_shared_from_this<Cls_X>) does not need to receive a type parameter (here Cls_X) that is a complete type.
template <typename T>
struct has_a_member { T mem; };
template <typename T>
struct has_a_pointer { T *ptr; };
struct A : has_a_member<A> // error at this point:
// A is incomplete at this point
// the definition of has_a_member<A> cannot be instantiated
{
};
struct B : has_a_pointer<B> // OK, B is incomplete
// still has_a_pointer<B> can be instantiated
{
};
And enable_shared_from_this is designed to work in that case, by expecting an incomplete type.
I'm trying to let the return type of doSomeMethod() be the same as the operator() in the base class but if it's declared as protected the compiler rejects the code with error: no type named 'type' in 'std::result_of'. It works if it's public but i wonder if I could get it working for the protected case too since.
Here is simple code reproducing the error.
#include <type_traits>
class base
{
protected:
int operator()(){return 1;};
};
class child : private base
{
auto static doSomeMethod()
-> typename std::result_of<base()>::type
{
return 1;
}
};
EDIT:
Ok thanks Kerrek SB and Dietmar Kühlr for your solutions and explanations. After playing around with it I found this solution that is more readable and works (at least in my real case where child is template class and base one of its template parameters) more reliable.
But it seems that it goes a bit against your explanations. Or is it just the way std::result_of<> is broken in this case?
#include <type_traits>
class base
{
protected:
double operator()(){ return 1; };
int operator()(int i){ return i; };
};
class child : private base
{
public:
auto operator()()
-> decltype(base::operator()())
{
return base::operator()();
}
auto operator()(int i)
-> decltype(base::operator()(std::declval<int>()))
{
return base::operator()(i);
}
};
Thanks for your time.
If your code is literally this, then you can exploit the fact that the protected operator() from base is also available in child, and use a simple trait:
template <typename> struct memfn_result;
template <typename C, typename R, typename ...Args>
struct memfn_result<R (C::*)(Args...)>
{
using type = R;
};
class base
{
protected:
int operator()(){ return 1; };
};
class child : private base
{
memfn_result<decltype(&child::operator())>::type a; // "a" is an "int"
};
Since base::operator()() is protected and you are using it on an object of type base rather than an object of type child you clearly can't access the member! You need to access the function call operator using an object of type child. Sadly, child is incomplete in the context where you are trying to access it, i.e., you need to an indirection:
class child
: private base {
auto static doSomeMethod()
-> decltype((std::declval<base>().*(&child::operator()))()) {
return 1;
}
};
According to http://msdn.microsoft.com/en-us/library/9ekhdcxs(v=vs.80).aspx,
C2079 can also occur if you attempt to declare an object on the stack of a type whose forward declaration is only in scope.
class A;
class B {
A a; // C2079
};
class A {};
Possible resolution:
class A;
class C {};
class B {
A * a;
C c;
};
class A {};
My question is how do I eliminate this error when I have the following situation:
class A; // Object
class B // Container
{
public:
typedef int SomeTypedef;
private:
A a; // C2079
};
class A {
void Foo(B::SomeTypedef);
};
I can't declare A before declaring B because A needs to use B's typedef, and I can't declare B before A because of this error.
One possible solution is to use a pointer to A instead of a stack variable, but I don't want a pointer (in this case).
Another solution is to not use typedef, or not to put it inside class B. But what if it belongs in B and I want not to pollute my project's namespace, as in B::SomeTypedef is a more appropriate name than SomeTypedef?
Your design is questionable, although perhaps nested classes is what you intend:
class B {
public:
typedef int SomeTypedef;
private:
class A {
void Foo(SomeTypedef);
};
A a;
};
If not, this can also be solved with another class which is common in CRTP code.
template<typename T>
struct foo;
class A;
class B;
template<>
struct foo<B> {
typedef int SomeTypedef;
};
class A {
void Foo(foo<B>::SomeTypedef);
};
class B : foo<B> {
private:
A a;
};
Or you can use another namespace.
Another method is use an intermediate class, plus pointers, its more long, but, it works:
This is header file, ( yes I know, "*.hpp" extension is not standard ):
ForwardClassExample.hpp
class ForwardClass {
public:
virtual void DoSomething();
};
class ContainerClass {
ForwardClass* Item;
/* constructor */ ContainerClass();
/* destructor */ ~ContainerClass();
};
class RealClass: ForwardClass {
/* override */ virtual void DoSomething();
};
This is body file:
ForwardClassExample.cpp
/* constructor */ ContainerClass::ContainerClass()
{
// create reference to forwaded class item
this.Item = new RealClass();
}
/* destructor */ ContainerClass::~ContainerClass()
{
// deletereference to forwaded class item
free this.Item();
}
void ForwardClass::DoSomething()
{
// ...
}
void RealClass::DoSomething()
{
// ...
}
Note:
I suggest to get used to apply pointers to variables, instead of direct fields, its may looks more difficult, at start, but, eventually allows to do more stuff.
It also prepare you to use "references" in case, one day you have to work with other programming languages.
Cheers.
Introduce the typedef where your design requires it, and then export it to wherever it makes the most sense for your user.
class A
{
public:
typedef int SomeTypedef;
void Foo(SomeTypedef);
};
class B
{
public:
typedef A::SomeTypedef SomeTypedef;
private:
A a;
};
Is there any possible way that a generic type can be used to contain a child of a base class.
From the assignment given to me, I am to create something similar to the following in structure.
template <class T>
class Fruit {
private:
int count;
int location_id;
T type;
public:
virtual void displayInfo();
};
class Apple : private Fruit<Apple> {
private:
int variety;
public:
void displayInfo() {
printf("Location %i has %i of %s in stock", location_id, count, variety);
}
};
Fruit<Apple> appleinventory[SIZE];
Basically, I think you can't have a template generic type be the same as a derived class. Am I wrong? Is there something similar that would possibly work?
Update:
For the assignment, I believe we are to use inheritance to show use of virtual functions. I've updated the code above. I think this would work, but does NOT need templates to be successful. We have not covered any advanced, redundant inheritance methods in class.
This is perfectly fine, in principle.
Read up about Curiously Recurring Template Pattern (CRTP) for more info on usage of derived class as the instantiating type in a class template that is its base, esp the example about static polymorphism which should look 'curiously' familiar.
template <class Derived> struct Base
{
void interface()
{
// ...
static_cast<Derived*>(this)->implementation();
// ...
}
static void static_func()
{
// ...
Derived::static_sub_func();
// ...
}
};
struct Derived : Base<Derived>
{
void implementation();
static void static_sub_func();
};
Ignoring questions of why you want to do this....you can get some of the way by doing this following:
template <class T> class Fruit
{
private:
int count;
int location_id;
T* type;
};
class Apple : private Fruit<Apple>
{
private:
int seeds;
bool red;
};
Fruit<Apple> appleinventory[SIZE];
Note the T* type is now a pointer to Apple rather than an instance of Apple.