I have code like that:
template<class T>
class A {
T a;
};
template<class T>
class C {
T c;
};
class B: protected A<C<B>> {
};
B b = B();
My intention is that the compiler should resolve that to (after substituting templates):
class B: protected A {
};
class C {
B c;
};
class A {
C a;
};
B b = B();
However it doesn't compile (the code from the first snippet (with templates)). The error is:
"Field has incomplete type B" in the line "T c".
So I modify it like that:
class B: protected A<C<B>> {
};
template<class T>
class A {
T a;
};
template<class T>
class C {
T c;
};
But then I had another problem. Generally, there is some problem with order of it, but I don't know how to declare it so that it compiles and doesn't throw "This type is incomplete" error or some other similar errors.
Related
I have a parent-class with a function. In this function I want to call a template method but the type of the template depends on the type of sub-class. So I want to save the information about T there. I can't call foo with a template because it's from another part of the Program wich i can't change
class A
{
//this will be called on an instance of B or C, A will never be
//instantiated
void foo()
{
ba<T>();
}
}
class B :public A
{
//T want to save here the Type of T so i won't have to call foo() with
//a template
}
class C :public A
{
//here comes another Type for T
}
What you need is a CRTP pattern, which is very common in C++ template programming.
template<class T>
void ba() {}
template<class Derived>
struct A
{
void foo() {
ba<typename Derived::MyT>();
}
};
struct B
: public A<B>
{
using MyT = int;
};
struct C
: public A<C>
{
using MyT = double;
};
int main() {
B b;
b.foo();
C c;
c.foo();
}
You will need to add a template parameter to the base class A and then specify the type in the declaration of B and C. See the example below:
template <typename T>
class A
{
public:
void foo()
{
ba<T>();
}
};
class B : public A<int>
{
};
class C : public A<bool>
{
};
int main()
{
B b;
C c;
b.foo(); // This calls ba<int>()
c.foo(); // This calls ba<bool>()
return 0;
}
It might be good to spend some time reviewing how templates and inheritance work.
Inheritance
Templates
I'm not sure if the following code is going to do what I expect it to:
struct Foo
{
// Some variables
};
struct Bar : public Foo
{
// Some more variables
};
struct Baz : public Foo
{
// Some more variables
};
class ExampleBase
{
Foo* A;
int B;
double C;
};
class ExampleBar : public ExampleBase
{
Bar* A;
}
class ExampleBaz : public ExampleBase
{
Baz* A;
}
void DoStuff(ExampleBase& example)
{
// Does things with the Foo*, doesn't need to know what inherited type it is
}
What happens when I have the same name for a pointer (A), which is derived from the same class, but is redefined in the derived Example classes?
I've tried templating the example class like this in order to avoid any ambiguity:
template <typename T>
class ExampleBase
{
T* A;
int B;
double C;
}
And then not deriving any classes from it. When I did this however, I can't get the DoStuff() function to compile. since I want it to accept any of the possible derived types.
Edit: The answers from the possible duplicate explain what happens, but don't solve the issue of a function using the base version
You may want to use a template for to implement DoStuff:
template<typename T>
void DoStuff(ExampleBase<T>& example)
{
// Does things with the T*
}
Alternatively, you can expose both the template and the polymorphic interface separately:
struct ExampleBase
{
int B;
double C;
virtual Foo* getA();
};
template<typename T>
struct ExampleTBase : ExampleBase
{
T* A;
Foo* getA() override { return A; }
};
void DoStuff(ExampleBase& example)
{
// Does things with the getA(), that returns a Foo*
}
This looks simple, but I have no good idea to solve this. Minimal example:
template<class T>
struct C {
typename T::t var;
};
class B;
struct A : public C<B> {
typedef int t;
};
struct B
{
A a;
};
int main() { return 0; }
I know that it can be solved by giving C less of B:
template<class t>
struct C {
t var;
};
struct A : public C<int> {
};
But this does not satisfy (especially because B has a lot of such typedefs and static functions I really need in C). Any better idea to resolve this?
If you can make A a template, then the following ought to work...
template<class T>
struct C {
typename T::t var;
};
template <typename BaseType>
struct A : public C<BaseType> {
int i;
};
struct B
{
typedef int t;
A<B> a;
};
typedef A<B> AType;
int main() {
AType a;
a.i = 1;
a.var = 1;
B c;
c.a.i =0;
return 0;
}
First if you want a class to be a base class, its type must be complete, like
struct A : public C<B>
in this case B must be complete type.
Second, if you declare a class type member its type need to be complete unless you define a pointer.
struct B
{
A a; // A must be complete type
};
So you can't have A inheriting from B and B having in as member. But you could convert one to pointer. For sample, below should be fine:
class A;
struct B
{
A* a; // imcomplete type is fine
typedef int t;
};
struct A : public C<B> {
};
Normally if you face this kind of issue, that means there is a design issue in your classes. Maybe you are making monolith classes.
If you follow good guide line:
1 one class (or function), one responsibility.
2 Where possible, prefer writing functions as nonmember nonfriends.
You will have less this kind of issues.
how can I implement such an idea in C++ without getting into "invalid use of incomplete type" trouble?
class A {
/*(...) some fields and methods here. */
class B {
/*(...) some fields and methods here. */
friend B A::fun();
};
B fun();
};
This works for me:
struct A {
class B;
B fun();
class B {
friend B A::fun();
};
};
I have a situation where I need to achieve polymorphism without vtable. Here is what I am trying to do
There is a class hierarchy: C extends B, B extends A
The idea is to declare a function pointer in A and constructors of B and C assign their corresponding methods to the function pointer in A
With the code below I am able to achieve polymorphism for class C but not for class B.
Obviously I am missing something here. I am not sure if this is even possible. Greatly appreciate any insights into this problem.
I can do this with the below code
A<C> *c = new C();
c->BasePrint(); //Reached C's Print
but not this
// A<B> *b = new B();
// b->BasePrint(); //Intentionally incorrect to demonstrate the problem.
Is there any way to achieve this?
template <typename T>
class A
{
public:
typedef void (T::*PrintFn)(void);
protected:
PrintFn printFn;
public:
void BasePrint()
{
if(printFn)
(((T*)this)->*printFn)();
}
};
template <typename T>
class B : public A<T>
{
public:
B()
{
printFn = &B::Print;
}
void Print()
{
//Print B
}
};
class C : public B<C>
{
public:
C()
{
printFn = &C::Print;
}
void Print()
{
//Print C
}
};
#include <iostream>
#include <typeinfo>
struct own_type {};
template<template<typename T>class CRTP, typename In, typename D>
struct DoCRTP: CRTP<In> {};
template<template<typename T>class CRTP, typename D>
struct DoCRTP<CRTP, own_type, D>: CRTP<D> {};
template<typename D>
struct A {
D* self() { return static_cast<D*>(this); }
D const* self() const { return static_cast<D*>(this); }
A() {
std::cout << "A<" << typeid(D).name() << ">\n";
self()->print();
}
};
template<typename T=own_type>
struct B:DoCRTP<A, T, B<T>> {
B() {
std::cout << "B<" << typeid(T).name() << ">\n";
}
void print() { std::cout<<"I am a B\n"; }
};
template<typename T=own_type>
struct C:DoCRTP<B, T, C<T>> {
C() {
std::cout << "C<" << typeid(T).name() << ">\n";
}
void print() { std::cout<<"I am a C\n"; }
};
void test() {
std::cout << "Instance of B<>:\n";
B<> b;
std::cout << "Instance of C<>:\n";
C<> c;
}
int main() {
test();
}
Here we have a way you can pass in the most derived class, and if you pass in nothing you are assumed to be the most derived class.
However, there is a problem with your design -- A already fully knows its type situation, so there is no need for virtual behavior! BasePrint could static_cast<T*>(this)->Print() and you'd do away with your overhead.
The fundamental problem you have is that you are storing specific-type member function pointers in your base class A.
A template-less A could store pointers to non-specific type function pointers -- say "static" ones that explicitly take an A* as the first argument. In C++11, you could auto-build these functions from member functions. In C++03, std::bind should let you convert your member function pointers to D to functions that take an A* as the first argument.
You are not specifying the template parameter for B in:
A<B> *b = new B();
as opposed to its declaration:
template <typename T>
class B : public A<T>
You should go with something long the lines of:
A<B<X>> *b = new B<X>();
with X being a non templated type.
I can do this with the below code [...] but not this:
A<B> *b = new B();
b->BasePrint(); //Intentionally incorrect to demonstrate the problem.
Well, the problem here is that B is a class template, and you are not instantiating it. It doesn't have much to do with polymorphism nor with vtables. A class template is just a blueprint (well, a template in fact) for instantiating types by passing arguments to them, but it is not a type per se.
You should use some template arguments when instantiating B. For instance:
A<C>* b = new B<C>();
b->BasePrint();
And you should see this invoking B::Print(). Here is a live example.