If I have a template class defined as:
#ifndef A_HPP
#define A_HPP
template<class T>
class A
{
public:
int doSomething(int in, bool useFirst);
private:
template<int CNT>
class B
{
public:
int doSomething(int in);
};
B<2> first;
B<3> second;
};
#include "a_imp.hpp"
#endif
Now I can go about having a declaration for A::doSomething in an implementation header file like this
#ifndef A_IMP_HPP
#define A_IMP_HPP
template<class T>
int A<T>::doSomething(int in, bool useFirst)
{
if (useFirst)
return first.doSomething(in);
return second.doSomething(in);
}
#endif
However I do not know how I go about making the declaration for the child class's method. Is it even possible or do I have to do one of the other two ways I can think of doing this, namely defining the methods in the main header or declare the class outside of A.
Please note that I am using C++11 so if this is only doable in that it will still work for me, though a C++98 solution would be good for other people.
You can do it in the following way:
template <class T>
template <int CNT>
int A<T>::B<CNT>::doSomething(int in)
{
// do something
}
Not sure if this is what you're asking, but I guess you need something like this:
template<class T>
template<int CNT>
int A<T>::B<CNT>::doSomething(int in)
{
return /*...*/;
}
Note that the template keyword appears twice, first for the template parameters of A, then for the parameters of nested class B.
Related
As part of my RTOSQueue implementation,
template<typename T,uint32_t number_of_elements>
class RTOSQueue : public RTOSQueueBase, public RTOSQueueInterlocutor<T>
{
...
};
I need to specialize some helper functions based on the type that's held in the queue:
template<typename T>
class RTOSQueueInterlocutor
{
public:
void AfterSuccessfulSend(T&message) {};
void AfterSuccessfulReceive(T&message) {};
};
The idea is some classes need a little help going in or going out, one of which is a reference counted buffer template:
template<typename T,
#ifdef RTOS_HEADER_INCLUDED
typename Atomifier=RTOSCriticalSection
#else
typename Atomifier=int32_t
#endif
>
class shared_buffer : public buffer_interface<T>
{
T* m_pPtr;
size_t m_uElements;
int* count;
...
};
(Pardon the Atomifier. It's there's for thread safety if you're using it with an RTOS)
In order to specialize this, I put this in my code:
template<>
void RTOSQueueInterlocutor<shared_buffer<MyBuffer>>::AfterSuccessfulSend(shared_buffer<MyBuffer>&message)
{
message.increment();
}
Then when I declare an RTOSQueue<shared_buffer> it all works fine and the Interlocutor increments the reference count upon a succesful send so it 'stays alive' inside the queue.
I'd LIKE to make this RTOSQueueInterlocutor specialization be "automatic", which would mean whenever I declare a shared_buffer<> object, it should also declare the RTOSQueueInterlocutor<> as well.
Is this possible? My attempts at putting it in the header file were unsuccesfull.
I tried putting:
#ifdef RTOS_HEADER_INCLUDED
template<typename T>
void RTOSQueueInterlocutor<shared_buffer<T>>::AfterSuccessfulSend(shared_buffer<T>&message)
{
message.increment();
}
#endif
Below my definition of shared_buffer<> template, and it didn't like that at all.
I have used the std::enable_if metafunction in my class template to specify that it is only allowed to generate classes for variables that have GameCard as a base class. This works fine on its own when I implement the functions inline. However, if I want to implement the template functions outside the header body I run into the issue that I can't figure out how to correctly specify the function that I want to implement.
Cut down example code:
#include <string>
#include <memory>
#include <vector>
struct GameCard {};
template<class T, class = std::enable_if_t<std::is_base_of<GameCard, T>::value>>
struct CardStack {
std::vector<T> cards;
bool Test();
};
My IDE generates this as the function specification:
template<class T, class>
bool CardStack<T, <unnamed>>::Test() {
return false;
}
This is obviously wrong since I'm getting compiler errors. But I don't have a clue on how to do it right. Do any of you know how to do this right?
Out of class definition should be:
template<class T, class Enabler>
bool CardStack<T, Enabler>::Test() {
return false;
}
But currently, you class might be hijacked:
Whereas CardStack<int> or CardStack<int, void> won't compile thanks to SFINAE,
CardStack<int, char> would be "valid" (risk to not compile because of hard error produced by int in CardStack implementation).
static_assert seems enough in your case:
template<class T>
struct CardStack {
static_assert(std::is_base_of<GameCard, T>::value);
std::vector<T> cards;
bool Test();
};
With simpler out of class definition:
template<class T>
bool CardStack<T>::Test() {
return false;
}
The function member definition should be something like:
template <class T, class U>
bool CardStack<T, U>::Test() {
// body of function
}
Live example
The explanation is pretty straightforward, there is no back magic here.
Just follow the normal syntactic rules of C++.
The definition of your class is a template class with two template parameters:
template<class, class>
struct CardStack { /* ... */ };
T is the name of the first one.
On the other hand, the second does not have any type-name, but only a default type (= ...).
Default type (similarly to default arguments for functions) does not have to be specified in the definition.
Therefore, the each method definition should be in the form:
template <class T, class U>
bool CardStack<T, U>::MethodName() {}
I am trying to create a vector class that looks something like this:
template <typename T>
class Vector
{
.
.
.
};
#include "vector.cpp"
However, when I start writing my functions in "vector.cpp", CLion complains that I have duplicate functions. How do I work around this? I believe in NetBeans, I can add vector.h & vector.cpp to a folder called "Important Files" which would fix the problem. I am not sure what the equivalent in CLion is.
General Design of a template
example.h
#ifndef EXAMPLE_H
#define EXAMPLE_H
// Needed includes if any
// Prototypes or Class Declarations if any
template<class T> // or template<typename T>
class Example {
private:
T item_;
public:
explicit Example( T item );
~Example();
T getItem() const;
};
#include "Example.inl"
#endif // EXAMPLE_H
Example.inl
// Class Constructors & Member Function implementations
template<class T>
Example<T>::Example( T item ) : item_(item) {
}
template<class T>
Example<T>::~Example() {
}
template<class T>
T Example<T>::getItem() const {
return item_;
}
Example.cpp
#include "Example.h"
// Only need to have the include here unless if
// the class is non template or stand alone functions
// are non-template type. Then they would go here.
I have a class that wraps logic for matrix management. Meanwhile I have a set of methods specialized in handling some important time spending matrix manipulation operations (like LU factorization and so on).
The class uses the functions defined in that file. That file needs to have access to that class' elements. I need to make those specialized methods friends of the above-mentioned class. This causes me to include one header in each other header.
My problem
The situation I described before is coded here as follows. The first code refers to mat.hpp.
#ifndef MAT_HPP
#define MAT_HPP
#include "operations.hpp"
namespace nsA {
template <typename T>
// Templated class because matrices can be real or complex
class mat {
// Members...
friend template <typename U>
void exec_lu(const mat<U>& in, const mat<U>& out);
// Members...
} /* class end */
}
#endif
#endif
The second file is operations.hpp
#ifndef OPERATIONS_HPP
#define OPERATIONS_HPP
#include "mat.hpp"
namespace nsA {
namespace nsB {
template <typename T>
void exec_lu(const mat<T>& in, const mat<T>& out);
}
}
#endif
The problem is that the compiler starts complaining.
Note
Consider please that if I comment the friend declaration in mat.hpp but leave the inclusions, the compiler tells me that in 'operations.hpp' type mat is not defined!
If also comment the inclusion in mat.hpp and keep friend declaration commented as well, the compiler is ok!
How to work on this?
Thankyou
You can do this by just adding a couple of forward declarations... But you can even do better with a bit more code:
template <typename T> class mat;
template <typename T> void exec_lu( const mat<T>&, const mat<T>& );
template <typename T>
class mat {
friend void exec_lu<T>( const mat<T>&, const mat<T>& );
};
template <typename T>
void exec_lu( const mat<T>& a, const mat<T>& b ) { ... }
The main difference between this approach and yours (other than fixing the syntax limitations) is that in this approach a single instantiation of exec_lu is granted access to mat<T>, in particular the instantiation that needs access to it. In your code (after fixing), all specializations of exec_lu would have access to any specialization of mat (i.e. exec_lu<int> could access mat<int> private members, but also mat<double>...) and you probably don't want that.
For a longer description of the different options to declare friends of a template, read this answer to a related question.
To get this to work, you need to forward declare the class. It looks like this:
The file mat.hpp:
#ifndef MAT_HPP
#define MAT_HPP
namespace nsA {
template <typename T>
class mat;
namespace nsB {
template <typename T>
void exec_lu(const mat<T>& in, const mat<T>& out);
}
template <typename T>
class mat {
friend void exec_lu(const mat<T>& in, const mat<T>& out);
};
}
#endif
And the file operations.hpp:
#ifndef OPERATIONS_HPP
#define OPERATIONS_HPP
#include "mat.hpp"
namespace nsA { namespace nsB {
template <typename T>
void exec_lu(const mat<T>& in, const mat<T>& out);
}}
#endif
Your original declaration gives out more friendship than mine. Mine only grants friendship to the function that matches the typename of the class.
If I have a template class specification like so,
template <typename T>
class MyClass {
public:
void fun1();
// ...
void funN();
};
template <typename T>
void MyClass<T>::fun1() {
// definition
}
// ...
template <typename T>
void MyClass<T>::funN() {
// definition
}
If I change the class template to something else, say I add an extra parameter:
template <typename T, typename U>
class MyClass {
// ...
};
Then I have to change each function definition (fun1, ..., funN) to agree with the class template specification:
template <typename T, typename U>
void MyClass<T,U>::fun1() { //... }
Are there any strategies for avoiding this? Could I use macros e.g.
#define DFLT_TEMPLATE template<typename T, typename U>
#define DFLT_CLASS class<T,U>
DFLT_TEMPLATE
void DFLT_CLASS::fun1() { // ... }
Or is this considered bad practice?
To me, the benefits of using a macro here are far overshadowed by the drawbacks. Yes, if you use a macro then if you ever need to add an additional template parameter, you'll only need to make a single modification. But anyone else reading your code is probably going to vomit.
I mean, are you going to do this for every template you have? Your code will become infested with ugly macros.
How many member functions do you have that this is an issue?
I think either they are small enough to be defined within the class template or the adaption of their algorithms to an additional template parameter would by far outweigh the replacement of those function headers.
Also, your editor ought to do this for you in no time anyway.
yes you could but don't forget to use "#undef DFLT_TEMPLATE" and "#undef DFLT_CLASS" at the end of file to avoid compiler warnings if your project have several templates with same macros definitions
Inheritation is better than macro.
If you want to change only a few functions and variables, make the specialized class inherit a common class that provides common functions/variables.
As far as possible, put the function definitions in the class template definition. It's a template, so unless you're using Comeau compiler, it's not as if they're going to be off in a different TU.
If the functions use something which is defined in between the class definition and the function definition, then you can play tricks to make that thing dependent on a template parameter even when "really" it isn't. For example:
template <typename T>
struct Foo {
void usebar();
};
struct Bar {
int a;
Foo<int> circularity; // circular dependency between Foo and Bar
Bar() : a(3) {}
};
template <typename T> void Foo<T>::usebar() {
Bar b;
std::cout << b.a << "\n";
}
Becomes:
// we only have to write "same" once
template <typename T, typename U>
struct same {
typedef U type;
};
struct Bar;
template <typename T>
struct Foo {
void usebar() {
typename same<T,Bar>::type b;
std::cout << b.a << "\n";
}
};
struct Bar {
int a;
Foo<int> circularity; // circularity gone
Bar() : a(3) {}
};
Or actually in this case just:
struct Bar;
template <typename T, typename B = Bar>
struct Foo {
void usebar() {
B b;
std::cout << b.a << "\n";
}
};
struct Bar {
int a;
Foo<int> circularity;
Bar() : a(3) {}
};
All cases support the following code:
int main() {
Foo<int> f;
f.usebar();
}
I would consider this approach bad practice. What you are complaining about is that you have changed your design (you need an extra template parameter) and now want a kludge to save on typing?
Introducing macros is going to decrease the readability of your code. Preprocessor definitions certainly have their place, but personally I'd never advocate one on the grounds that I can't be bothered to change my functions.
There are probably some (more or less bad) workarounds, but you definitely point out a " missing" feature of C++: class namespace extension.
Some people already proposed to extend C++ in this way:
http://www.lrde.epita.fr/dload//20080709-Seminar/ordy-classnamespaces.pdf
namespace foo
{
class bar
{
typedef int baz_t;
baz_t my_method ();
};
}
namespace class foo::bar
{
baz_t my_method ()
{
// ...
}
}
--
Using a macro is not a good idea (usual things about macros ....).
I would prefer, at worst, write function members definitions inline in this case, or even better use an editor than can help you easily update your class definition.
Macros are bad because they let you write code editing functions where you are supposed to write programs.
If you want to edit code, use your editor (sed, M-x replace-*, Find&Replace ...)