Assume I have the following layout of my project where UtilsLib and DataLib are statically linked libraries:
// UtilsLib/SomeToolClass.h
class SomeToolClass
{
template<typename Object>
Object* doSomething()
{
// ...
return new Object();
}
template<typename Object>
void doSomethingElse()
{
// just here to show this class does a lot more than just doSomething()
}
};
// DataLib/Thing.h
class Thing
{
// ...
};
// MyProgram/main.cpp
#include "UtilsLib/SomeToolClass.h"
#include "DataLib/Thing.h"
int main()
{
SomeToolClass<Thing> tool;
tool.doSomething();
SomeToolClass<AnotherThing> tool2;
tool2.doSomething();
}
What I want to do is have a specialization for SomeToolClass<Thing>::doSomething. For example, if the method was virtual, I could just create a class with SomeToolClass<Thing> as the base class and override the method. For the purposes of this question, please assume that is not an option. I'm also stuck with the library layout.
Can I define a template specialization in one library for a template class defined in another? How can I do this?
Related
I have an application class that can take in a dependent class as a template argument to the constructor. This dependent class is required to provide certain templated functions that the application class can call. I would like to offload this dependent class object to a pimpl class so the application class is not a template class and thus header-only.
Here is a rough idea of what I mean.
///////////
// impl.h
///////////
template<typename Helper>
struct Impl
{
public:
Impl(Helper& helper) : helper_(helper)
{
}
template <typename T>
void someHelperFn1(T t)
{
helper_->fn1(t);
}
template <typename U>
SomeOtherClass<U> someHelperFn2()
{
return helper_->fn2();
}
private:
Helper& helper_;
};
///////////
// app.h
///////////
#include "impl.h"
class App
{
public:
template<typename Helper>
App(Helper &h) :impl_(new Impl) {}
template <typename T>
void someHelperFn1(T t)
{
impl_->someHelperFn1(t);
}
template <typename U>
SomeOtherClass<U> someHelperFn2()
{
return impl_->someHelperFn2();
}
void someAppFn();
private;
std::unique_ptr<Impl> impl_;
};
///////////
// app.cpp
///////////
void App::someAppFn()
{
// some useful code
}
I realize the above code doesn't compile since Impl is really a template class and so App would also be a template class too. That is what I would like to avoid so that App is not a header-only class. I found something similar except the functions that I want to call from the helper dependency are template functions and they are not in this case. It seemed pretty close otherwise to what I wanted to do.
Any ideas on how I can avoid making App a template class?
I tried making the helper class use a common base class but that is not really possible with the template functions.
Also, note that I am limited to C++ 17 for the compiler.
You will need to make sure the public header file (the one with the class that has the pimpl pointer) doesn't expose the header file only class template of the implementation. Use an interface for that like this.
I did not dependency inject the implementation because that should not be needed.
#include <memory>
#include <iostream>
// public header file
// for pimpl pattern I often use an interface
// (also useful for unit testing later)
class PublicItf
{
public:
virtual void do_something() = 0;
virtual ~PublicItf() = default;
protected:
PublicItf() = default;
};
// the public class implements this interface
// and the pimpl pointer points to the same interface
// added advantage you will have compile time checking that
// the impl class will all the methods too.
class PublicClass final :
public PublicItf
{
public:
PublicClass();
virtual ~PublicClass() = default;
void do_something() override;
private:
std::unique_ptr<PublicItf> m_pimpl; // the interface decouples from the template implementation (header file only)
};
// private header file
// this can now be a template
template<typename type_t>
class ImplClass final :
public PublicItf
{
public:
void do_something() override
{
m_value++;
std::cout << m_value << "\n";
}
private:
type_t m_value{};
};
// C++ file for Public class
// inlcude public header and impl header (template)
PublicClass::PublicClass() :
m_pimpl{ std::make_unique<ImplClass<int>>() }
{
};
void PublicClass::do_something()
{
m_pimpl->do_something();
}
// main C++ file
int main()
{
PublicClass obj;
obj.do_something();
return 0;
}
This is the first time I am using class templates so please don't be to harsh if I made a simply mistake.
I have a class template class A<class T>. It has a method init() that is pure virtual and therefore will be implemented separately in every derived class. What all these possible derived classes will have in common is an init(T* i_x) which basically does some general stuff and then calls the init(). Because this will be the same for every derived class I want to define it in the base class template already. But somehow my compiler doesn't find the right function.
If I try to use the init(T* i_x) on an object of a derived class A_der I get the error:
no matching function for call to 'A_der::init(B_der*)
The classes used for the template parameter T will all be derived from another class B. Therefore the error message involves the class B_der which is derived from class B.
I boiled the problem down to a small example, which should involve everything that is important for the problem. If I try to compile this example in Visual Studio (normally I work in STM32CubeIDE) I get the following error
Severity Code Description Project File Line Suppression State
Error C2660 'A_der::init': function does not take 1
arguments template_class-overload_inherited_method [...]\main.cpp 8
So somehow the only function the compiler finds at this point is init() but not the base class template method init(T* ).
Can somebody please tell me why it is like that and what can I do to get the behaviour I want (without implementing a similar init(T* ) in every derived class of A?
Here is my example code:
base class template A - declaration - A.hpp
template<class T>
class A
{
protected:
T* m_x;
public:
virtual void connect(T* i_x) final;
virtual void init() = 0;
virtual void init(T* i_x) final;
};
base class template A - implementation - A.cpp
#include "A.hpp"
template<class T>
void A<T>::connect(T* i_x)
{
//some checks
m_x = i_x; //connects object of B to A
}
template<class T>
void A<T>::init(T* i_x)
{
connect(i_x);
init();
}
derived class A_der
#include "A.hpp"
#include "B_der.hpp"
#pragma once
class A_der : public A<B_der>
{
void init() override;
};
void A_der::init()
{
//Initialization which needs a B_der connected already
}
main.cpp
#include "B_der.hpp"
#include "A_der.hpp"
int main(void)
{
B_der testB;
A_der testA;
testA.init(&testB);
return 0;
}
For the sake of completeness:
class B
{
};
class B_der : public B
{
};
EDIT - Solved
Thanks a lot for the fast replies.
The combination of the comments from #BoP and #Jarod42 solved the problem.
I had to unhide the method with using A<B_der>::init (actually renaming might be the more elegant way) and move the implementation of A into A.hpp.
I will offer the updated example which builds successfully with Visual Studio 2019 for me here:
base class A
template<class T>
class A
{
protected:
T* m_x;
public:
virtual void connect(T* i_x) final;
virtual void init() = 0;
virtual void init(T* i_x) final;
};
template<class T>
void A<T>::connect(T* i_x)
{
//some checks
m_x = i_x; //connects object of B to A
}
template<class T>
void A<T>::init(T* i_x)
{
connect(i_x);
init();
}
derivad class A_der
A_der.hpp
#include "A.hpp"
#include "B_der.hpp"
class A_der : public A<B_der>
{
public:
void init() override;
using A<B_der>::init;
};
A_der.cpp
#include "A_der.hpp"
void A_der::init()
{
//Initialization which needs a B_der connected already
}
main.cpp
#include "B_der.hpp"
#include "A_der.hpp"
int main(void)
{
B_der testB;
A_der testA;
testA.init(&testB);
return 0;
}
for completeness
B.hpp
class B
{
};
B_der.hpp
#include "B.hpp"
class B_der : public B
{
};
I also forgot to make the methods of A_der public in the earlier example, this is corrected here. And I removed the #pragma onces in this example.
class A_der : public A<B_der>
{
void init() override;
};
When you declare a function init in the derived class, it hides all things named init from the base class. This is just like when declaring something in an inner scope - it hides things with the same name from outer scopes.
There are ways to import the hidden names, but an easy solution would be to just chose a different name, like init_base. Or, probably better, pass a parameter to the class constructor.
I am writing a class C which has an inner class T, and I'd like the details of T hidden as an internal implementation of C. Methods in C are all using pointers to T. This is of course possible as:
// In header
class C {
public:
class T;
T* f();
void g(T*);
};
// In .cpp
class C::T { /* details here */ };
Now my question is, how can I define C::T as a type alias of another one, in .cpp file. The following doesn't compile at all, but it illustrates what I want to do:
// Outside the class C
using C::T = std::string;
Is there any workaround to this, while maintaining the goal, i.e. hide the detail of C::T?
As others pointed out, it cannot be done. This is my suggestion:
// .h
class C {
public:
struct T;
T* f();
void g(T*);
};
// .cpp
struct C::T
{
IMPL_TYPE data;
//If one is carefull with lifetimes this can almost in any context act as IMPL_TYPE.
//And if necessary, the data member can be accessed.
operator IMPL_TYPE&(){return data};
}
You cannot, because the forward declaration class T; within class C declares a class type whose True Name is C::T, and is therefore not identical to the type whose True Name is std::basic_string<...>.
You might consider the following:
// C.h
#include "internal/T.h"
namespace foo {
class C {
public:
using T = internal::T;
// ...
};
}
// internal/T.h
namespace foo { namespace internal {
using T = std::string;
}}
The closest you can come to this would be to have your t derive from string:
class C::T : public std::string { ... };
T can never be truly hidden or redefined to be a type alias in a different .cpp file.
The following round about method should work for your needs.
class C
{
public:
// Use a base class for just the pointers.
struct TBase
{
virtual ~TBase() {}
};
TBase* f();
void g(TBase*);
// Allow client code to define a concrete type using a template parameter.
template <typename Data> struct T : TBase
{
Data data;
};
};
Then, in a .cpp file, use:
using Type = C::T<std::string>;
Type* obj = new Type;
obj->data = "Some string";
C c;
c.g(obj);
TBase* ptr = c.f();
How do I use pimpl for a templated class, when I explicitly instantiate the templates?
All I need is an example code.
What I have tried is:
// MyTemplatedClass.h
template< class T >
class MyTemplatedClass
{
private:
class Impl;
Impl* _pimpl;
public:
void PublicMethod();
}
Here my implementation goes:
// MyTemplatedClass.cpp
template< class T >
class MyTemplatedClass<T>::Impl
{
public:
void PublicMethod();
}
template <class T>
void MyTemplatedClass<T>::Impl::PublicMethod()
{
...
}
Forwarding method call to implementation class:
template< class T >
void MyTemplatedClass<T>::PublicMethod()
{
_pimpl->PublicMethod();
}
Explicit instantiation:
Example with int and double:
template class MyTemplatedClass< int >;
template class MyTemplatedClass< double >;
But it doesn't seem to work.
This would answer your question, but I doubt it does what you hoped to achieve. I suspect you would want to declare the template implementation outside the scope of MyTemplatedClass. It might be a better design to inherit from the template implementation instead of having it as a member variable.
If you compiler does not support extern template declarations I cannot see that having a template pointer to implementation adds any value. You would after all have to have the implementation details you wanted to hide away in the header file anyway.
#include <iostream>
template < class T > class MyTemplatedClass {
private:
template < class U> class Impl {
public:
void ImplPublicMethod() {
std::cout << "Standard implementation" << std::endl;
}
};
Impl<T> * _pimpl;
public:
MyTemplatedClass() : _pimpl(new Impl<T>) { }
~MyTemplatedClass() { delete _pimpl; }
void publicMethod() {
_pimpl->ImplPublicMethod();
}
};
template<> class MyTemplatedClass<int> {
private:
class Impl {
public:
void ImplPublicMethod() {
std::cout << "Integer specialisation" << std::endl;
};
};
Impl * _pimpl;
public:
MyTemplatedClass() : _pimpl(new Impl) { }
~MyTemplatedClass() { delete _pimpl; }
void publicMethod() {
_pimpl->ImplPublicMethod();
}
};
int main(int argc, char ** argv) {
MyTemplatedClass<char> charVersion;
charVersion.publicMethod();
MyTemplatedClass<int> intVersion;
intVersion.publicMethod();
return 0;
}
Methods of a template class always have to be defined in the header. You cannot have a MyTemplatedClass.cpp as compilation unit on its own. What you can do is to #include the file containing the definitions of the methods at the end of MyTemplatedClass.h so that declaration and definition are at least separated at file level. So your problem may be fixed by adding
#include "MyTemplatedClass.cpp"
at the end of MyTemplatedClass.h.
I use pimpls with template classes in my own code, it works for me that way. Your code looks about right - I'd use a std::unique_ptr for pimpl, but I don't see any problems with how you're doing it.
I'm having an issue with a C++ library I'm trying to write. It's the usual setup, one cpp file, one header file. I want the header file to only expose the parts that are meant to be used (I have an abstract base class for instance, I don't want in the header file). So far, I'm just working with a single file (I assume this should make no difference, as includes are done by the preprocessor, which doesn't care about anything).
You'll note that the "header file" is spread over two spots, before and after the header implementation file.
#include <stdio.h>
// lib.h
namespace foo {
template <class T> class A;
}
// lib.cpp
namespace foo {
template <class T> class A {
private:
T i;
public:
A(T i) {
this->i = i;
}
T returnT() {
return i;
}
};
};
// lib.h
namespace foo {
template <class T> T A<T>::returnT();
}
// foo.cpp
void main() {
foo::A<int> a = foo::A<int>(42);
printf("a = %d",a.returnT());
}
So, naturally, I'd like my header file to contain just
namespace foo {
template <class T> class A;
template <class T> T A<T>::returnT();
}
But my compiler does not like this (it complains that returnT is not a member of foo::A<T>. The reason I don't want to put the class declaration itself in the header is that then it would (as I understand it), contain all the private and similar stuff, which I'd like to hide.
Maybe it's just me, but the following header file seems "bad", at least as an "interface specification." It exposes some of the internals of A, which a user of the lib would not need to know about.
// lib.h
namespace foo {
template <class T> class A {
private:
int i;
public:
A(T);
T returnT();
};
}
// lib.cpp
namespace foo {
template <class T> A<T>::A(T i) {
this->i = i;
}
template <class T> T A<T>::returnT() {
return i;
}
};
Is this the accepted way of doing it? I'd like a more abstract header file, if at all possible.
You cannot separate the definition of a template from its declaration. They both have to go into the header file together.
For "why?" I recommend reading "Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?".
I may have misread your question. To address what may also be your question, this is not valid:
namespace foo {
template <class T> class A;
template <class T> T A<T>::returnT();
}
It is not valid for the same reason that this is not valid:
namespace foo {
class A;
int A::returnT();
}
Member functions must be declared inside the definition of the class.
There are two problems with .cpp files you are dealing here:
I.
If you want to put an instance of that class on the stack (like you do in your main()) the compiler needs to know the size of the class (to allocate enough memory). For that it needs to know the members and by that the complete declaration.
The only way to hide the class' layout away is to built up an interface and a factory method/function and put the instance on the heap in the factory.
As an example (without the template; see below to know why):
namespace foo {
class IA {
public:
virtual ~IA();
virtual int returnT() = 0;
static IA *Create();
};
}
In your .cpp you then do:
namespace foo {
class A : public IA {
private:
int i;
public:
A() :
i(0) {
}
virtual ~A() {
}
virtual int returnT() {
return i;
}
};
IA::~IA() {
}
IA *IA::Create() {
return new A();
}
}
BTW: Using smart pointers would be suggested...
II.
Since you are using a template the method definitions must be either visible via header file or explicitly instantiated for a specific set of types.
So you can split up your code into a lib.h and a lib_impl.h:
lib.h:
namespace foo {
template <typename T> class IA {
public:
virtual ~IA() {
}
virtual T returnT() = 0;
static IA *Create();
};
}
lib_impl.h:
namespace foo {
template <typename T> class A : public IA<T> {
private:
T i;
public:
A() :
i(T()) {
}
virtual ~A() {
}
virtual T returnT() {
return i;
}
};
template <typename T> IA<T> *IA<T>::Create() {
return new A<T>();
}
}
so you include the lib_impl.h where ever you need the impleemntations.
To use the explicit instantiations add a lib.cpp and just let that file allow to include lib_impl.h:
lib.cpp:
#include <lib_impl.h>
namespace foo {
template class IA<int>;
template class A<int>;
template class IA<float>;
template class A<float>;
template class IA<char>;
template class A<char>;
// ...
}