I have the following template class:
// A.hpp
class A_data {
public:
int foo = 1;
virtual ~A_data() = default;
};
template <class C = A_data> class A {
public:
int foo() const; // Not implemented here
A() { d = new C; }
~A() { delete d; }
C* d;
};
I implement the default instance of A:
// A.cpp
#include "A.hpp"
// Template source implementation
template <> int A<A_data>::foo() const { return d->foo; }
Now, I can use the class with the default instance:
// main.cpp
#include <iostream>
#include "A.hpp"
int main() {
A a;
std::cout << a.foo(); // Prints 1
}
However, suppose I want to create a class which inherits A, along with its own data class which inherits A_data, like so:
// A.hpp
class B_data : public A_data {
public:
int bar = 2;
virtual ~B_data() = default;
};
// Template here is in case something needs to inherit B, like in A.
template <class C = B_data> class B : public A<C> {
public:
int bar() const; // Not implemented here, just like A::foo.
};
// A.cpp
template <> int B<B_data>::bar() const { return d->bar; }
This results in the following problem:
#include <iostream>
#include "A.hpp"
int main() {
B b;
std::cout << b.bar(); // Works fine, prints 2
std::cout << b.foo(); // Linker error: no implementation of A<B_data>::foo!
}
As you can probably glean from the example, the intent is to have a class with its own data container (in this case A and A_data), such that other classes can inherit it (B), and can optionally choose to expand the data container by inherting the parent's container (B_data).
I can get around this problem by defining the implementation in A.hpp, but in this case I don't want to provide multiple interfaces of A other than A_data and its derived classes. If I really wanted to, I could implement each instance in A.cpp, but it adds nothing of value since the implementation itself is invariant.
My expectation was that B<B_data> would be able to "know" about A<A_data> and use A <A_data>::foo, since B inherits from A. Obvously, since B<B_data> and B<A_data> are not related, this is not the case -- but can it be?
Can I achieve this "expanding class" interface without exposing the implementation in the header? If not, is there a better alternative that would still allow me to maintain this simple interface?
Part of the reason templates seemed to be appealing here as opposed to regular class inheritence is because they allow to automatically dereference the correct container data without doing any type of pointer casts. Example with regular classes:
#include "A.hpp"
int A::foo() const { return d->foo; }
int B::bar() const { return d->bar; } // Compiler error: No member 'bar' in 'A_data'
If you want to stick to templates, you can implement this 'mirrored inheritance' as follows: make B<B_data> inherit from A<A_data> instead of A<B_data> by declaring in B_data (or other possible template argument types) an alias base to a whatever type you want to consider base for your purposes (it's ambiguous in general, since there may be many bases of a class) and making B<C> inherit from A<C::base>. Then, for B<C>, since d is of type C::base*, it can still hold a pointer to C which is derived from C::base (assuming C::base is set adequately and is an actual base). But in this case, we need to provide a custom default constructor in B so that it constructs C object for d, not C::base which would happen if default constructor for A<C::base> would be called by implicitly defaulted default constructor of B<C> (note that there's no need to provide destructor since delete d from A<C::base>'s destructor will work correctly if C::base has virtual destructor). Then, since inside B<C> we know how we constructed the object d points to, we can safely assume we know its dynamic type and access it through static_cast-ed pointer (for safety you could e.g. add dynamic_cast-check inside assert for Debug-builds check).
Example implementation (see also comments, in particular for some changes of other aspects of your code):
// A.hpp
class A_data {
public:
int foo = 1;
virtual ~A_data() = default;
};
template <class C = A_data> class A {
public:
int foo() const;
A() { d = new C; }
// 'virtual' is not strictly needed in our particular case since we don't delete B
// through A*, but still it is safer and best practice with it than without
virtual ~A() { delete d; }
C* d;
};
class B_data : public A_data {
public:
using base = A_data;
int bar = 2;
// virtual ~B_data() = default; implicitly defaulted and virtual
};
template <class C = B_data> class B : public A<typename C::base> {
public:
B() { this->d = new C; } // 'this' needed to trigger dependent name lookup
int bar() const;
};
// A.cpp
#include "A.hpp"
template <> int A<A_data>::foo() const { return d->foo; }
template <> int B<B_data>::bar() const { return static_cast<B_data*>(d)->bar; }
// main.cpp
#include <iostream>
#include "A.hpp"
int main() {
B b;
std::cout << b.bar();
std::cout << b.foo();
}
Note also that if you want to use different template arguments C, you may want to avoid code duplication in specialization definitions in A.cpp. There, you can define your templated functions usually (not as specializations), but to force instantiations use explicit template instantiations. E.g. suppose there's B_data_2 class defined like this:
// in A.hpp
class B_data_2 : public A_data {
public:
using base = A_data;
int bar = 3;
};
It also has bar public data member, but with different default initializer. Now we can add another specialization for B<B_data_2>::bar() to A.cpp, but it will be basically the same as B<B_data>::bar(), so code duplication arises:
// in A.cpp
template <> int A<A_data>::foo() const { return d->foo; }
template <> int B<B_data>::bar() const { return static_cast<B_data*>(d)->bar; }
template <> int B<B_data_2>::bar() const { return static_cast<B_data_2*>(d)->bar; }
Instead, if we replace specializations with general definitions followed by explicit instantiation definitions of methods, we have:
// in A.cpp
template<class C> int A<C>::foo() const { return d->foo; }
template int A<A_data>::foo() const;
template<class C> int B<C>::bar() const {
return static_cast<C*>(this->d)->bar; // Again 'this' to enable dependent name lookup
}
template int B<B_data>::bar() const;
template int B<B_data_2>::bar() const;
This obviously scales better, but to avoid doing explicit instantiation for every member function of the same specialization, we can do even better - explicitly instantiate whole class specializations, which will, in particular, automatically instantiate all (non-templated) member functions of that specializations:
// in A.cpp
template<class C> int A<C>::foo() const { return d->foo; }
template<class C> int B<C>::bar() const {
return static_cast<C*>(this->d)->bar; // Yet again 'this' to enable dependent name lookup
}
template class A<A_data>;
template class B<B_data>;
template class B<B_data_2>;
Now we can test and see that it compiles and works:
// main.cpp
#include <iostream>
#include "A.hpp"
int main() {
B b;
B<B_data_2> b_2;
std::cout << b.bar() << b.foo() << std::endl; // 21
std::cout << b_2.bar() << b_2.foo() << std::endl; // 31
}
Putting implementation in header would be fine in your case, and you don't need specialization:
class A_data {
public:
int foo = 1;
virtual ~A_data() = default;
};
template <class C = A_data>
requires(requires(C c) { c.foo; } ) // Possibly, in C++20
class A
{
public:
int foo() const { return d->foo; }
A() = default;
std::unique_ptr<C> d = std::make_unique<C>();
};
class B_data : public A_data {
public:
int bar = 2;
virtual ~B_data() = default;
};
// Template here is in case something needs to inherit B, like in A.
template <class C = B_data>
requires(requires(C c) { c.foo; c.bar;} ) // Possibly, in C++20
class B : public A<C> {
public:
int bar() const { return this->d->bar; }
};
#include <iostream>
int main() {
B b;
std::cout << b.bar();
std::cout << b.foo();
}
Demo
The problem is that you've explicitly specialized foo for the template argument A_data instead of B_data.
To solve this just change the explicit specialization to be for the argument B_data as shown below:
A.cpp
#include "A.hpp"
//----------------vvvvvv---------------------------------->changed from A_data to B_data
template <> int A<B_data>::foo() const { return d->foo; }
template <> int B<B_data>::bar() const { return d->bar; }
main.cpp
#include <iostream>
#include "A.hpp"
int main() {
B b;
std::cout << b.bar(); // Works fine, prints 2
std::cout << b.foo(); // WORKS FINE, prints 1
}
Working demo
The output of the above modified program is:
21
Explanation
B is instantiated with B_data and so it inherits from A<B_data>. Note carefully that it inherits from A<B_data> and not A<A_data>. This means that foo's implementation for A<B_data> should be provided. But you never provided foo's implementation for A<B_data> because what you actually provided was implementation of foo for A<A_data> and hence the error. Thus by changing A_data to B_data as shown in the modified code above, we get rid of the error.
Related
class A{
public:
void printer(){
B obj;
obj.private_data = 10; // <- fails, says member inaccessible
}
}
class B{
friend void A::printer();
private:
int private_data;
}
is it possible for printer function to access private members of class B? i tried to pass an obj of B as arg to printer but it still failed
Class A doesn't know about B to use it. Hence, postpone the definition of the function printer() until you define B, and if you need an instance of B to be a member var in A then make a forward declaration for B to declare a B* in A.
Hence, use something like what follows:
class A {
public:
void printer();
};
class B {
friend void A::printer();
private:
int private_data;
};
void A::printer() {
B obj;
obj.private_data = 10; // <- No longer fails
std::cout << obj.private_data;
}
int main() {
A a;
a.printer();
}
Demo
Why Friend Function cannot access private members of a class?
They can, but you may need to split the definition of the class up a bit.
Imaginary files added:
Define A (file a.hpp):
class A {
public:
void printer();
};
Define B (file b.hpp):
#include "a.hpp" // B must see the definition of A to befriend a member function
class B {
friend void A::printer();
private:
int private_data;
};
Define A's member function (file a.cpp):
void A::printer() {
B obj;
obj.private_data = 10;
}
To access B, you first need to define it. Thus, you can just declare the method printer and define it after you have defined the class B.
class A {
public:
void printer();
};
class B {
private:
friend class A;
int private_data;
};
void A::printer() {
B obj;
obj.private_data = 10;
}
Note, you probably want to move your methods out of your class definition anyways and into a separate .cpp file. Methods defined inside the class are implicitly marked as inline which might not be what you expect.
Is there a way to have a template class such as this
template<bool state = true>
class A
{
};
and have another class which can accept both A<true> and A<false> as a argument or field, without being a template class itself. Like this:
class B
{
public:
B(A& arg_a)
: a(arg_a)
{}
private:
A& a;
};
int main()
{
A<true> aTrue;
A<false> aFalse;
B bTrue(aTrue);
B bFalse(aFalse);
};
Or is this simply impossible because two objects of the same class with different template arguments are treated as different types by the compiler? Other suggestions on how to design this would also be appreciated. I know this design is possible if I just make the template parameter a class field, but I'd like to know if this can be done using templates parameters.
Or is this simply impossible because two objects of the same class with different template arguments are treated as different types by the compiler?
The two different specializations A<true> and A<false> of the class template A are indeed different types.
You could either overload the constructors of B to allow each of them:
struct B {
B(const A<true>&);
B(const A<false>&);
}
or you could leverage polymorphism with any specialization of A deriving from a common base class:
#include <ios>
#include <iostream>
struct Base {
virtual bool getState() const = 0;
};
template<bool state = true>
struct A : public Base {
bool getState() const override { return state; }
};
struct B {
bool state;
B(const Base& base) : state(base.getState()) {}
};
int main() {
A<true> a1{};
A<false> a2{};
std::cout << std::boolalpha
<< B(a1).state << " " // true
<< B(a2).state; // false
}
Another alternative, as mentioned by #Jarod42 in the comments, is to use std::variant, given that you are using C++17 (or later); particularly, std::variant<A<true>, A<false>>.
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
Suppose I have the following class definitions
struct base {
virtual int f() = 0;
};
struct A: public base {
int f() final { return 1; }
};
struct B: public base {
int f() final { return 2; }
};
Is it possible to turn A and B into templates that take a bool parameter that specifies whether to inherit from the base or not? I have usage cases that do or don't require a base class providing a common interface.
Assume that A and B have a lot of member functions, so duplicating implementation would be tedious. But sizeof(A) and sizeof(B) are small.
Sure:
template <bool> struct A
{
// ...
};
template <> struct A<true> : base
{
// ...
};
(Note that you could make A<true> derive from A<false> if that avoids redundancy.)
For example:
template <bool> struct A
{
void f() { std::cout << "A::f called\n"; }
};
template <> struct A<true> : A<false>, base
{
void f() override { A<false>::f(); }
};
int main()
{
A<false> a1;
A<true> a2;
a1.f();
a2.f();
static_cast<base&>(a2).f();
}
I came up with the more direct approach I was looking for, without code duplication.
struct base {
virtual int f() = 0;
};
struct empty_base { };
template <bool Inherit>
struct A final: public std::conditional_t<Inherit,base,empty_base> {
int f() { return 1; }
};
Since you are using a pure base class the distinction shouldn't be important as your optimizer will avoid the virtual function call when you call A::f() since there will never be a derived class that implements a different version of f().
Also you can instead do class A final : base if you don't plan on inheriting from A to avoid having to add final to each function.
I am not sure how to ask this, but hopefully someone will understand. Lets say I have 3 different classes. Class A, Class B and Class C. Class C should take either Class A or Class B as a parameter in the constructor and store it in a private variable.
This is easy with overloaded constructors. My question is how can Class C automagically use the correct class depending on what constructor was used? (Note these 2 classes are similar, but come from different libraries and thus no shared base class). Is this possible with templates? I do not have a lot of experience with templates.
You can do it quite easy with templates:
class A;
class B;
template<class AorB>
class C
{
public:
C(AorB aorb)
: aorb_(aorb)
{ }
private:
AorB aorb_;
};
What this does is that inside the class C the identifier AorB can be used as any other class, in fact it doesn't even have to be an instance of A or B but can be any class.
Can be used like this:
A myA;
B myB;
C<A> myCWithA(myA);
C<B> myCWithB(myB);
There is however one thing you have to remember when creating classes using templates: The specification and implementation can no longer be split into separate header and source files. All of the code have to be available in the header file.
The syntax of the member functions are also a little different.
Example:
template<class T>
class C
{
public:
...
void someFunction();
};
template<class T>
C<T>::someFunction()
{
...
}
Yes, this is possible with templates:
#include <iostream>
template<class T>
class C {
public:
C(T const& ref) : ref(ref) {}
void doStuff() const {
ref.doStuff();
}
private:
T ref;
};
class A {
public:
void doStuff() const {
std::cout << "A::doStuff" << std::endl;
}
};
class B {
public:
void doStuff() const {
std::cout << "B::doStuff" << std::endl;
}
};
int main() {
C<A> foo((A()));
foo.doStuff();
C<B> bar((B()));
bar.doStuff();
}