Template wrangling - c++

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);
}
};

Related

Use base class implementation when base is template type

I have a class that receives its base type as a template arg and I want my derived class to call a function, print. This function should use the derived implementation by default but if the base class has a print function it should use the base implementation.
#include <iostream>
class BaseWithPrint {
public:
static void print(int i) { std::cout << "Base::print\n"; }
};
class BaseWithoutPrint {
};
template <typename B>
class Derived : public B {
public:
static void print(bool b) { std::cout << "Derived::bool_print\n"; }
template <typename T>
static void print(T t) { std::cout << "Derived::print\n"; }
void Foo() {
print(1);
print(true);
print("foo");
}
};
int main()
{
Derived<BaseWithPrint> d1;
d1.Foo();
Derived<BaseWithoutPrint> d2;
d2.Foo();
return 0;
}
This code only ever calls the Derived version of print.
Code can be seen at
https://onlinegdb.com/N2IKgp0FY
If you know that the base class will have some kind of print, then you can add using B::print to your derived class. If a perfect match isn't found in the derived, then it'll check the base.
Demo
To handle it for the case where there may be a base print, I think you need to resort to SFINAE. The best SFINAE approach is really going to depend on your real world situation. Here's how I solved your example problem:
template <class T, class = void>
struct if_no_print_add_an_unusable_one : T {
// only ever called if derived calls with no args and neither
// the derived class nor the parent classes had that print.
// ie. Maybe best to force a compile fail:
void print();
};
template <class T>
struct if_no_print_add_an_unusable_one <T, decltype(T().print(int()))> : T {};
//====================================================================
template <class B>
class Derived : public if_no_print_add_an_unusable_one<B> {
using Parent = if_no_print_add_an_unusable_one<B>;
using Parent::print;
public:
// ... same as before
};
Demo

Two template classes with methods calling each other

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();
}

Circular dependency with template function

I have a class A with the following declaration (A.h file):
#ifndef __A_DEFINED__
#define __A_DEFINED__
class A
{
public:
template<typename T> inline void doThat() const;
};
#endif
and a class B deriving from that class (B.h file):
#ifndef __B_DEFINED__
#define __B_DEFINED__
#include <iostream>
#include "A.h"
class B : public A
{
public:
void doThis() const { std::cout << "do this!" << std::endl; }
};
#endif
So far, so good. My issue is that the function A::doThat() uses B::doThis():
template<typename T> inline void A::doThat() const { B b; b.doThis(); }
Usually, the circular dependency would not be an issue because I would just define A::doThat() in the .cpp file. In my case however, doThat is a template function so I can't do that.
Here are the solutions I have envisioned so far:
Defining the template function A::doThat() in a .cpp file. The issue with that is that I need to instantiate explicitly all the calls with various template arguments (there might be many in the real case).
After the declaration of the A class in A.h, add #include "B.h" and then define the A::doThat() function. This works fine in visual studio but g++ does not like it.
Is there a neat way to solve this problem?
EDIT: In the real case, there is not just one child class B, but several (B, C, D, etc.) The function A::doThat() depends on all of them. The function B::doThis() is also templated.
A default template parameter for the B class could work:
#include <iostream>
// include A.h
class B;
class A
{
public:
template<typename T, typename U = B> inline void doThat() const
{
U b; b.doThis();
}
};
// include B.h
class B : public A
{
public:
void doThis() const { std::cout << "do this!" << std::endl; }
};
// main
int main()
{
A a;
a.doThat<int>();
}
Usually the best way to allow a parent to call a child function is to declare the function as a pure virtual function in the parent and override it in the children.
#include <iostream>
class A
{
public:
virtual ~A() = default;
template<typename T> inline void doThat() const
{
// do some other stuff
doThis();
}
virtual void doThis() const = 0; // pure virtual function
};
class B: public A
{
public:
void doThis() const override
{
std::cout << "do this!" << std::endl;
}
};
int main()
{
B b;
A* ap = &b;
ap->doThat<int>();
}
The following does work with g++:
File A.h:
#ifndef __A_DEFINED__
#define __A_DEFINED__
class A
{
public:
template<typename T> inline void doThat() const;
};
#include "B.h"
template<typename T> inline void A::doThat() const { B b; b.doThis(); }
#endif
File B.h:
#include <iostream>
#include "A.h"
// We check for the include guard and set it AFTER the inclusion of A.h
// to make sure that B.h is completely included from A.h again.
// Otherwise the definition of A::doThat() would cause a compiler error
// when a program includes B.h without having included A.h before.
#ifndef __B_DEFINED__
#define __B_DEFINED__
class B : public A
{
public:
void doThis() const { std::cout << "do this!" << std::endl; }
};
#endif
File test_A.cpp:
// In this test case we directly include and use only A.
#include "A.h"
#include "A.h" // We test whether multiple inclusion causes trouble.
int main() {
A a;
a.doThat<int>();
}
File test_B.cpp:
// In this test case we directly include and use only B.
#include "B.h"
#include "B.h" // We test whether multiple inclusion causes trouble.
int main() {
B b;
b.doThat<int>();
b.doThis();
}
Alternative Idea:
I do not know whether you (or some coding conventions) insist on separate header files for each class, but if not the following should work:
You can put the definitions of class A and class B and of the member function template A::doThat<typename>() (in this order) together in one header file AandB.h (or whatever name you like).
This cries for polymorphism. There are two options using polymorphism:
Dynamic polymorphism, i.e. make A an abstract base class and call doThis() virtually:
struct A
{
virtual void do_this() const = 0;
template<typename T>
void doThat() const { doThis(); }
};
struct B : A
{
void doThis() const override { /* ... */ }
};
Of course, this only works if doThis() is not templated. If you need that, you could use
Static polymorphism, i.e. CRTP, when
template<typename Derived>
struct A
{
template<typename T>
void doThat() const { static_cast<const Derived*>(this)->template doThis<T>(); }
};
struct B : A<B>
{
template<typename T>
void doThis() const { /* ... */ }
};
If (as in your example code) B::doThis() is not called for the same object, but for some temporary, you could
template<typename typeB>
struct A
{
template<typename T>
void doThat() const { typeB b; b.template doThis<T>(); }
};

C++ circular dependency issue with function templates

I have several classes in a project I'm working on; the first is a Solver class, originally with a function template whose full definition is in the Solver header file, like so (just showing the bare necessities):
solver.h
class Solver {
public:
template<typename T>
void solve(T t);
}
template<typename T>
void Solver::solve(T t) {
// implementation here
}
Now, class A is used as template parameter for the solve function template as follows:
A.h
#include "solver.h"
class A {
private:
Solver s; //s is instantiated in constructor
public:
void doSomething();
}
A.cpp
void A::doSomething() {
s.solve<A&>(*this);
}
So this is all fine and dandy as it is now, but for the purposes of the project, I need to move the definition of the solve() function template into an implementation file (solver.cpp) from the header file. As I understand it, I can do this as long as I add lines that explicitly state what types will be used with the function template, as follows:
solver.cpp
template<typename T>
void Solver::solve(T t) {
// implementation here
}
template void Solver::solve<A&>(A& a);
However this doesn't work when I try to compile solver, because in order to specify A as a type I want to use as a template parameter in solve.cpp, I need to have A not be an incomplete type. But A requires Solver in order to even compile - so I believe I have a circular dependency. Is there any way I can get around this issue?
I'm relatively new to all this, so take it easy on me please :) Much thanks.
Samoth is nearly right, you need class A; ("forward declaration"). But only before you use it, not before the Solver class:
Edited In response to comments, your minimal code sample was too minimal :) The real problem was Header Guards:
#ifndef SOLVER_H_INCLUDED_
#define SOLVER_H_INCLUDED_
class Solver {
public:
template<typename T>
void solve(T t);
};
#endif // SOLVER_H_INCLUDED_
And
// A.h
#ifndef A_H_INCLUDED_
#define A_H_INCLUDED_
#include "Solver.h"
class A {
private:
Solver s; //s is instantiated in constructor
public:
void doSomething();
};
#endif // A_H_INCLUDED_
// Solver.cpp
#include "Solver.h"
#include "A.h"
template<typename T>
void Solver::solve(T t) {
// implementation here
}
// explicit instantiations
template void Solver::solve<int>(int);
// ...
template void Solver::solve<A&>(A&);
This will work
// main.cpp
#include "A.h"
int main()
{
A a;
a.doSomething();
}
The best way to pass-by circular dependencies is to do this :
class A; // before the class Solver
class Solver {
public:
template<typename T>
void solve(T t);
}
template<typename T>
void Solver::solve(T t) {
// implementation here
}
What you can do is:
solver.h
#ifndef SOLVER_H_INCLUDED_
#define SOLVER_H_INCLUDED_
class Solver {
public:
template<typename T>
void solve(T t);
};
#include "solver.cpp"
#endif
solver.cpp
#include "solver.h"
template<typename T>
void Solver::solve(T t) {
// implementation here
}
and a.hpp
#ifndef A_H_INCLUDED_
#define A_H_INCLUDED_
#include "solver.h"
class A {
private:
Solver s; //s is instantiated in constructor
public:
void doSomething()
{
s.solve(*this);
}
};
#endif

Invalid use of incomplete type on g++

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();
}
};