Two template classes have two methods each which call the other class's method:
// Foo.h
template<typename T>
class Foo {
public:
static void call_bar() {
Bar<int>::method();
}
static void method() {
// some code
}
};
// Bar.h
template<typename T>
class Bar {
public:
static void call_foo() {
Foo<int>::method();
}
static void method() {
// some code
}
};
How can I get this to work? Simply adding #include "Bar.h" to Foo.h (or vice versa) doesn't work because each class needs the other one.
EDIT: I also tried forward declarations, but it still fails at linking stage:
// Bar.h
template <typename T>
class Foo {
public:
static void method();
};
// Foo.h
template <typename T>
class Bar {
public:
static void method();
};
When you have two class templates that are dependent on each other, using two .h files does not make sense. In order to be able to use Foo, you need both Foo.h and Bar.h. In order to be able to use Bar, you also need both Foo.h and Bar.h. It's best to put them in one .h file.
Define the classes.
Implement the member functions at the end.
FooBar.h:
template<typename T>
class Foo {
public:
static void call_bar();
static void method() {
// some code
}
};
template<typename T>
class Bar {
public:
static void call_foo();
static void method() {
// some code
}
};
template<typename T>
void Foo<T>::call_bar() {
Bar<int>::method();
}
template<typename T>
void Bar<T>::call_foo() {
Foo<int>::method();
}
Related
I'm having an issue where I've created a somewhat tangled hierarchy involving templates. The result is I'm having to put some code in the wrong header files just to get it to compile, and compilation is now fragile (I don't know if I can keep this project compiling if just the right function needs to be added.)
So I'm looking for a way to resolve this so that the code is nicely divided into proper files.
So without further ado, here is the code:
TemplatedBase.h
template <typename T> struct TemplatedBase
{
T value;
void go();
};
Derived.h
struct Derived : public TemplatedBase<int>
{
void hello()
{
printf("HI %d\n", value);
}
};
template <typename T> void TemplatedBase<T>::go()
{
// TemplatedBase<T> NEEDS USE OF Derived!!
// So TemplatedBase<T>::go() is appearing here in Derived.h,
// that's the only way I could get it to compile and it seems really
// out of place here.
Derived der;
der.hello();
}
main.cpp
#include <stdio.h>
#include "Derived.h"
int main(int argc, const char * argv[])
{
Derived d;
d.go();
return 0;
}
Isn't there a way I can put TemplatedBase<T>::go() into a file like TemplatedBase.cpp? Alas, it doesn't seem to work (you will see Undefined symbol: TemplatedBase<int>::go() in XCode at least).
You could do it by explicitly instantiating the template with a particular type in the cpp file:
// TemplatedBase.cpp
#include "TemplatedBase.h"
#include "Derived.h"
template <typename T>
void TemplatedBase<T>::go()
{
// TemplatedBase<T> NEEDS USE OF Derived!!
// So TemplatedBase<T>::go() is appearing here in Derived.h,
// that's the only way I could get it to compile and it seems really
// out of place here.
Derived der;
der.hello();
}
template struct TemplatedBase<int>; // This will make it work but now you can only use `TemplatedBase<int>`
// More instantiations go here...
But I wouldn't recommend doing this as this restricts what types you are able to use in TemplatedBase<T> (You'd have to manually add every single type yourself). So instead, use a templated type inside the go() member function (The trick here is that template parameters are not evaluated immediately):
// TemplatedBase.h
struct Derived; // Forward declaration
template <typename T>
struct TemplatedBase
{
T value;
void go()
{
go_impl();
}
private:
template <typename X = Derived>
void go_impl()
{
X der;
der.hello();
}
};
// Derived.h
#include "TemplatedBase.h"
struct Derived : public TemplatedBase<int>
{
void hello()
{
printf("HI %d\n", value);
}
};
Note: BTW, since C++20, one can just do:
// TemplatedBase.h
struct Derived; // Forward declaration
template <typename T>
struct TemplatedBase
{
T value;
void go()
{
[] <typename X = Derived>() {
X d;
d.hello();
}();
}
};
TemplatedBase and Derived are really coupled, so sharing the same header might be a viable option.
Else, you can create a file for your template definition (Header guards omitted):
// TemplatedBase.h
// Public header
#include "TemplatedBaseDecl.h"
#include "TemplatedBaseImpl.h"
// TemplatedBaseDecl.h
template <typename T>
struct TemplatedBase
{
T value;
void go();
};
// TemplatedBaseImpl.h
#include "TemplatedBaseDecl.h"
#include "Derived.h"
template <typename T> void TemplatedBase<T>::go()
{
Derived der;
der.hello();
}
// Derived.h
// Public header
#include "TemplatedBaseDecl.h" // Cannot use "TemplatedBase.h"
struct Derived : public TemplatedBase<int>
{
void hello()
{
printf("HI %d\n", value);
}
};
I have a sprite class, which has a templatised data member. It holds an object, which has a pointer to this specialised sprite template class.
That object requires a forward declaration of my sprite class, but since sprite is a template class, I need to include the full header. Therefore I get a cyclic dependancy which I am unable to figure out
Sprite.h
#include "myclass.h"
template<typename SpriteType, typename = typename std::enable_if_t<std::is_base_of_v<sf::Transformable, SpriteType> && std::is_base_of_v<sf::Drawable, SpriteType>>>
class Sprite {
public:
SpriteType s;
myclass<SpriteType>;
Sprite() {
}
auto foo() {
return s;
}
private:
};
myclass.h
#include "Sprite.h"
//a sprite of type T, is going to create a myclass<Sprite<T>>, a pointer of the Sprite<T> is held in myclass.
template<typename T>
class myclass
{
public:
std::shared_ptr<Sprite<T>> ptr;
myclass() {
}
private:
};
How could I solve this cyclic dependency?
So in summary:
-Sprite is a template class.
-Sprite holds an object to another class. This other class holds a pointer to my this templated sprite class.
-This gives me a cyclic dependency, since both classes are now templates, and need to have their implementations written in their header files.
Simplified decoupling, based on #Taekahns solution.
template<typename T>
class myclass
{
public:
std::shared_ptr<T> ptr;
myclass() {
}
private:
};
template<typename SpriteType, typename = typename std::enable_if_t<std::is_base_of_v<sf::Transformable, SpriteType> && std::is_base_of_v<sf::Drawable, SpriteType>>>
class Sprite {
public:
SpriteType s;
// DO NOT PASS SpriteType here, put the whole Sprite<SpriteType>
myclass<Sprite<SpriteType>> t;
Sprite() {
}
auto foo() {
return s;
}
private:
};
One of the great thing about templates is breaking type dependencies.
You could do something like this. Simplified for readability.
template<typename T>
class myclass
{
public:
std::shared_ptr<T> ptr;
myclass() {
}
private:
};
template<typename SpriteType, typename = std::enable_if_t<std::is_base_of_v<base_class, SpriteType>>>
class Sprite {
public:
SpriteType s;
myclass<Sprite<SpriteType>> t;
Sprite() {
}
auto foo() {
return s;
}
private:
};
That is one of many options.
Another option is to use an interface. i.e. a pure virtual base class that isn't a template.
Example:
I think something like this should do it. Starting to get a hard to follow though.
class base_sprite
{
public:
virtual ~base_sprite(){};
virtual int foo() = 0;
};
template<typename T>
class myclass
{
public:
std::shared_ptr<base_sprite> ptr;
myclass() : ptr(std::make_shared<T>())
{
};
};
template<typename SpriteType>
class Sprite : public base_sprite{
public:
myclass<Sprite<SpriteType>> l;
int foo() override {return 0;};
};
I've got 2 classes with methods that call each other. One of them is a template method:
// Foo.h
class Foo {
public:
void foo_method() {
Bar::bar_method();
}
template <typename U>
static void foo_other_method() {
// some code
}
};
// Bar.h
class Bar {
public:
static void bar_method() {
Foo::foo_other_method<int>();
}
};
And I call it like this:
Foo f;
f.foo_method();
How should I arrange the #include directives in Foo.h and Bar.h so this code compiles?
Move the implementation of Foo::foo_method() so that the definition of Bar is available.
Since it is not a function template, you can move it to a .cpp file.
Foo.h:
#pragma once
class Foo {
public:
void foo_method();
template <typename U>
static void foo_other_method() {
// some code
}
};
Bar.h:
#pragma once
// Need this so Foo::foo_other_method() can be used.
#include "Foo.h"
class Bar {
public:
static void bar_method() {
Foo::foo_other_method<int>();
}
};
Foo.cpp:
#include "Foo.h"
#include "Bar.h"
void Foo::foo_method()
{
Bar::bar_method();
}
I want to have a template that can access the protected method of it's typename parameter. How can I make that work?
For example:
class Foo{
...
protected:
int Bar();
}
template <class T> FooTempl{
...
int SomeMethod(T* ptr) { return ptr->Bar();};
...
}
The reason is that I want the method Foo::Bar() to be accessible to the template, but not to any other external caller. I hope there's some friend syntax there that can make it work...
An alternate to declaring FooTempl as a friend of Foo would be to have the former derive from the latter. In this case, since Foo is a base class for FooTempl, so FooTempl::SomeMethod would not need to have a Foo * parameter anymore.
class Foo
{
protected:
int Bar() { return 42; }
};
template <class T>
class FooTempl : public T
{
public:
int SomeMethod() { return T::Bar();}
};
int main()
{
FooTempl<Foo> bar;
bar.SomeMethod();
}
Which of these methods is more appropriate depends on your use case.
Add the following line into Foo:
template<typename T> friend class FooTempl;
I have two classes that depend on each other:
class Foo; //forward declaration
template <typename T>
class Bar {
public:
Foo* foo_ptr;
void DoSomething() {
foo_ptr->DoSomething();
}
};
class Foo {
public:
Bar<Foo>* bar_ptr;
void DoSomething() {
bar_ptr->DoSomething();
}
};
When I compile it in g++, it was giving error of "Invalid use of incomplete type", but it was compiled nicely in MSVC 10.
Is it possible to solve this problem while keeping the declaration and definition in one header file? (no cpp files)
If this is not allowed in the standard, so is this one of the MSVC "bug" or "feature"?
Yes, just move the method definitions out of the class definition:
class Foo; //forward declaration
template <typename T>
class Bar {
public:
Foo* foo_ptr;
void DoSomething();
};
class Foo {
public:
Bar<Foo>* bar_ptr;
void DoSomething() {
bar_ptr->DoSomething();
}
};
// Don't forget to make the function inline or you'll end up
// with multiple definitions
template <typename T>
inline void Bar<T>::DoSomething() {
foo_ptr->DoSomething();
}
See this page:
What is the best way to deal with co-dependent classes in C++?
It should clear up the problem and provides a couple nice solutions.
It works when you replace Foo* foo_ptr; by the template parameter T so that you get T* foo_ptr;. In this foo_ptr does not necessarily have to be a pointer or be predefined.
template <typename T>
class Bar {
public:
T foo;
void DoSomething() {
foo.DoSomething();
}
};
class Foo {
public:
Bar<Foo>* bar_ptr;
void DoSomething() {
bar_ptr->DoSomething();
}
};