I would appreciate some assistance in a (for my level anyways) rather complicated template problem.
Let me explain my 'system' first.
Modeling a basic audio mixing and streaming system, it has three building components:
A Buffer, from which the Player will process data from.
Since they are directly connected by data, their data needs to by of the same type. Thus Buffer<T> ~ Player<T> , here the templates must match.
These are wrapped in Manager, who will eventually manage all the incoming buffers into one player.
Now, both Buffers and Players would need some different implementations, thus they are represented by generic interfaces as iPlayer and iBuffer.
My goal is to be able to declare a manager like this:
simple_manager<simple_player<float>>;
or failing this at least
simple_manager<simple_player , float>;
Since im not sure the first one even has a solution, my attempt at the second was thus:
template <typename K>
class iManager {
private:
K player;
};
template <template <typename> class C , typename T>
class simple_manager : iManager< C<T> > {
public:
void play(iBuffer<T> & _buffer,const audio_descriptor ad, bool * condition){
player.play(_buffer,ad,condition);
}
};
As you can see, in the concrete class, T marks the type of the data to be manipulatod, while C is the concrete class of player i wish to use.
The interface has only one template which marks the concrete player class again. So K ~ C<T>
This does not compile with (only) the following error:
simple_manager.cpp: In member function ‘void simple_manager<C, T>::play(iBuffer<T>&, audio_descriptor, bool*)’:
simple_manager.cpp:18:12: error: ‘player’ was not declared in this scope
player.play(_buffer,ad,condition);
^~~~~~
And i do not know what causes this. Can the compiler not deduce that T must be inherited from iPlayer, since iPlayer must implement a play() method.
I can get it to actually work if I define simple_manager like this:
class simple_manager : iManager< simple_player<float> > {...}
but it still won't work with:
class simple_manager : iManager< simple_player<T> > {...}
I am stumped. If i had <T extends iPlayer> from Java, this would work, but compilation-time templating is a tougher nut i guess.
Any help would be greatly appreciated!
The first issue is that player is inaccessible from the derived class because it's marked private instead of protected. You could make it protected or add some protected member function to access it:
template <typename K>
class iManager {
protected:
K player;
};
This still won't work, however, because iManager<C<T>> is a dependent base class, so its members are hidden from unqualified name lookup. To get around this, you can access it through the this pointer:
void play(iBuffer<T> & _buffer,const audio_descriptor ad, bool * condition){
this->player.play(_buffer,ad,condition);
}
To get the nice usage in your first example, you could write a trait to extract a template argument from given type:
template <typename T> struct extract_inner;
template <template <typename> class C, typename T>
struct extract_inner<C<T>> { using type = T; };
template <typename T>
using extract_inner_t = typename extract_inner<T>::type;
Then that can be used to supply the correct argument to iBuffer:
template <typename T>
class simple_manager : iManager< T > {
public:
void play(iBuffer<extract_inner_t<T>> & _buffer,
const audio_descriptor ad, bool * condition){
this->player.play(_buffer,ad,condition);
}
};
Live demo
Your problem is quite simple.
You got almost all the syntax right, but you miss one thing: the this keyword.
When you extend a class that depending on a template parameter, this become kind of a dependent name. Since the base class is a template that depends on the a template parameter on your child, the compiler must know which name come from the base and which does not. If the compiler would not request to remove the ambiguity, one could specialize your base class, throw a bunch on names and make your child class use them.
To remove the ambiguity, simply add this-> keyword in front of the name that come from the base class:
template <template <typename> class C , typename T>
struct simple_manager : iManager< C<T> > {
void play(iBuffer<T> & _buffer,const audio_descriptor ad, bool * condition){
this->player.play(_buffer,ad,condition);
}
};
Related
EDIT: I didn't actually get a chance to test out any of the suggested solutions as I went on a vacation, and by the time I was back, the people responsible for the class template had made some changes that allowed me to get around the need to use types defined in the class template itself.
Thanks to everyone for their help though.
In a nutshell - and feel free to correct my wording, templates are still a bit of voodoo to me, - I need to know if I can use a (protected) struct or a #typedef defined inside a class template from my specialized class. For example:
This is the class template:
template<typename T>
class A : public C<T>
{
protected:
struct a_struct { /* Class template implementation, doesn't depend on T */ };
void foo( a_struct a );
};
Which I need to fully specialize for T = VAL:
template<>
class A< VAL > : public C< VAL >
{
void foo( a_struct a )
{
// My implementation of foo, different from the class template's
}
};
If I do something like this, however, the compiler complains that a_struct is undefined in my specialized class. I tried specializing and inheriting from the class template but that got... messy.
I saw some solutions, but all of them involved modifying the class template, which is something I am not able to easily do (different team).
Thoughts?
No, you can't use members of the primary template declaration in your specialization of the class template. That is because in essence a template class specialization declares a completely new class template that is applied when the template arguments match the specialization.
You have two options available though, if you want to do something like in your example:
You can specialize the template class member function. This is useful if it is indeed only one member function that is special (or at least the number of member functions is limited).
You can bring the declaration of the member (-type) in a common base class.
Since you indicated in an edit that you can't change the class template itself, specializing the member function seems the best option.
A simplified example of specializing a member function only
template< class T>
class Printer
{
public:
struct Guard {};
void DoPrint( const T& val)
{
Guard g;
(void)g;
std::cout << val << '\n';
}
};
struct Duck {};
template<>
void Printer<Duck>::DoPrint( const Duck& val)
{
Guard g;
(void)g;
std::cout << "Some duck\n";
}
The Guard here is only used to demonstrate that this type is available to both the primary and the specialized implementation of DoPrint().
It's not beautiful, but you can do it like this:
template<typename T>
class C
{
};
template<typename T>
class A : public C<T>
{
protected:
friend A<int>;
// ^^^^^^
struct a_struct { /* Class template implementation, doesn't depend on T */ };
void foo( a_struct a );
};
template<>
class A< int > : public C< int >
{
using a_struct = typename A<void>::a_struct;
// ^^^^^^
void foo( a_struct a )
{
// My implementation of foo, different from the class template's
}
};
or how about, re-declaring struct a_struct in the specialized template, with same functionality as default one.
I know it may not sound good since you need to inject in all specialized templates. But that is one i can think of now.
I have a template and many derived classes. In all of these classes I want to use the template type and some dependent types of it (actually I have many types and many dependent types).
The following approach is quite bad, since I need to manually inherit (with using keyword) all the types from the parent class (see code example):
EDIT: I didn't know that it is important that the class where I want to use the types is also a template. I updated the code example accordingly.
template<class T>
class A {
using TBase = T;
using TDerived = T[10];
}
template<class T>
class B : A<T> {
// NOTE i want the types TBase and TDerived here and in further children
using TBase = A<T>::TBase;
using TDerived = A<T>::TDerived
}
class C : B<int> {
// NOTE i want the types TBase and TDerived here and in further children
using TBase = B<int>::TBase;
using TDerived = B<int>::TDerived
}
I also thought about templated namespaces so that I could define the types outside of the class - but they don't exist.
Does anyone have a better idea?
SOLUTION1: fix current approach
(based on the comments from Jan Hudec and the answer from Oguk)
public inheritance
I forget the keyword public: for classes (struct is public by default).
missing typename
The compiler warning for my (wrong) types where used in the class where misleading (although the ones for the using keyword directly hint to the missing typename keyword).
Further notes about when to use typename can be found here: https://stackoverflow.com/a/7923419/3779655
type interitance
When I correctly specify the type (e.g. see 2. missing typename) then I can also use the current class name.
Resulting code:
template<class T>
class A {
public:
using TBase = T;
using TDerived = T[10];
};
template<class T>
class B : public A<T> {
public:
// possiblity 1:
using TBase = typename B::TBase;
TBase memberB1;
// possibility 2
typename B::TBase memberB2;
};
class C : public B<int> {
public:
// NOTE C is no template -> we don't have to do anything
TBase memberC;
};
SOLUTION2: trait classes
(based on the answer from Oguk)
use templated trait class instead of namespace
This gives pretty much the same functionality.
different availability of type information
One thing I didn't think of before is to check which type information is available where and if further characters are needed to retrieve the needed type information from a parent class (see NOTE comments).
See code below:
template<class T>
struct TypesContainer {
using TBase = T;
using TDerived = T[10];
};
template<class T>
class A {
public:
// TODO possible to directly inherit all types?
//using TypesContainer<T>;
// NOTE this is only possible for methods, not types
using Types = TypesContainer<T>;
typename Types::TBase memberA;
};
class B : public A<int> {
public:
// NOTE here I have all template information via definition (by hand)
using Types = TypesContainer<int>;
typename Types::TBase memberB;
};
class C : public B {
public:
// NOTE here I don't have the type information any more
using Types = TypesContainer<A::Types::TBase>;
typename Types::TBase memberC;
};
PROBLEM:
Is there a way to directly inherit all members of a namespace/class within the class scope (see TODO comment). Using the using keyword without assignement operator = does only work for methods not namespaces, classes and types.
First, if you are otherwise fine with your design, it should work if you inherit the base class publicly. This would work in the code you posted. However, if your example is very simplified, there might be another reason you cannot access the typedefs in your real code: The thing which could cause problems for you is if your derived class is actually also a templated class with the type parameter T, e.g. B<T>. This would make the base class A<T> dependent and its members would not considered during lookup if you use a non-dependent name (i.e. only TBase) to refer to them inside B<T>, so they would not be found. Referring to them as typename A<T>::TBase would solve that problem by making the name dependent names.
If you want to follow your other idea and have that type information available outside of the class (because it is conceptually more connected to T and not so much to the class A), instead of the "templated namespaces" you were thinking of, usually, trait classes are used for this purpose:
template <class T>
struct MyTraits {
using TBase = T;
using TDerived = T[10];
}
Then you can access those using declarations (or, alternatively, typedefs) from anywhere by using MyTraits<T>::TBase. This is effectively what you would achieve with a templated namespace. Don't forget to add the typename keyword if you use the using/typedef members of MyTraits in a dependent context, i.e. typename MyTraits<T>::TBase.
I'd like to place a POD type constrain on type parameter T of class template A and then derive another class template B from the satisfactory A. Besides, B is supposed to have different implementation according to constancy of instance of A. The purpose of doing all this is about, well you know, for better type checking before runtime.
All I can figure out is a tentative definition of A
template <typename T, typename POD=void>
class A;
template <typename T>
class A <T, std::enable_if<std::is_pod<T>::value>::type>
{
//blah...
};
so that A can't be instantialized when passing non-POD type, as you might have noticed that partial parameterization does the trick like a type switch.
But I can't figure out how B could be defined. I presume it looks like the following
template <typename A?>
class B;
template <>
B<const A?> : public A?
{
//blah...
};
template <>
B<A?> : public A?
{
//blah...
};
Any brilliant idea?
PS: Personally I tend to be highly critical. But just post how you think this could be done anyway.
There is no brilliant idea if the specializations are going to be completely different. You have to go with this:
template <typename T>
class B;
template <typename T>
class B<const A<T>> : public A<T>
{
};
template <typename T>
class B<A<T>> : public A<T>
{
};
which is almost same as you've written yourself except ? symbol.
You can instantiate this class as:
B<A<int>> x; //it chooses the second specialization
B<const A<int>> y; //it chooses the first specialization
See online demo. Note that you've forgotten typename here:
typename std::enable_if<std::is_pod<T>::value>::type
I fixed that too.
If some code in the specializations are going to be same, then you could do some trick in order to share the common part, but I cannot suggest anything as I don't know what you're going to put in the specializations.
I have two simple class that I made just to understand how friend class works. I am confused as to why this doesn't compile and also would the Linear class have access to the struct inside Queues class?
Linear.h
template<typename k, typename v >
class Linear
{
public:
//Can I create a instance of Queues here if the code did compile?
private:
};
Linear.cpp
#include "Linear.h"
Queues.h
#include "Linear.h"
template<typename k, typename v >
class Linear;
template<typename x>
class Queues
{
public:
private:
struct Nodes{
int n;
};
//Does this mean I am giving Linear class access to all of my Queues class variable or is it the opposite ?
friend class Linear<k,v>;
};
Queues.cpp
#include"Queues.h"
My errors are
Queues.h:15: error: `k' was not declared in this scope
Queues.h:15: error: `v' was not declared in this scope
Queues.h:15: error: template argument 1 is invalid
Queues.h:15: error: template argument 2 is invalid
Queues.h:15: error: friend declaration does not name a class or function
To answer your initial question:
the friend keyword inside a class let the friend function or class access otherwise private field of the class where the friend constraint is declared.
See this page for a thorough explanation of this language feature.
Regarding the compilation errors in your code:
In this line:
friend class Linear<k,v>;
ask yourself, what is k, where is it defined? Same for v.
Basically, a template is not a class, it's a syntactic construct letting you define a "class of class", meaning that for the template:
template <typename T>
class C { /* ... */ };
you don't have yet a class, but something that will let you define class if you provide it a proper typename. Within the template the typename T is defined, and can be used in place as if it were a real type.
In the following code snippets:
template <typename U>
class C2 {
C<U> x;
/* ... */
};
you define another template, which when instantiated with a given typename will contain an instance of the template C with the same typename. The typename U in the line C<U> x; of the code above, is defined by the including template. However, in your code, k and v don't have such a definition, either in the template where they are being used, or at the top level.
In the same spirit, the following template:
template <typename U>
class C2 {
friend class C<U>;
/* ... */
};
when instantiated, will have the instance of the class template C (again with the same parameter U) as a friend. As far as I know, It is not possible to have class template instances be friend with a given class, for all possible parameters combinations (The C++ language doesn't support existential types yet).
You could, for instance, write something like:
template<typename x>
class Queues
{
public:
private:
struct Nodes{
int x;
};
friend class Linear<x,x>;
};
to restrict the friendliness of Linear to only the instance of that template with x and x, or something like this:
template<typename x,typename k, typename v>
class Queues
{
public:
private:
struct Nodes{
int x;
};
friend class Linear<k,v>;
};
If you want to allow k and v to be defined ad lib.
Your problem is with templates not with friend classes in that code.
Friend just means that restrictions against access to private and protected are removed for that class. As if the word private in the class was public, basically.
Do try to submit code with one problem and which you understand all but one thing.
This occured in the line of thought following Template specialization or conditional expressions?.
I am using template specialisation in a project of mine and came across this example from Stroustrup: Matrix.h, where he declares a MatrixBase template class
template<class T> class Matrix_base
for common elements and a Matrix template class
template<class T = double, int D = 1> class Matrix
as a "prop" (whatever that is) for specialisations. He declares the constructor as private so that only specialisations can be instanciated. These are declared:
template<class T> class Matrix<T,1> : public Matrix_base<T> {...};
template<class T> class Matrix<T,2> : public Matrix_base<T> {...};
template<class T> class Matrix<T,3> : public Matrix_base<T> {...};
My question is: In this case, what is the advantage of specialisation? Obviously there is no code that the three specialisations have in common, so why not cut out the general template and declare:
template<class T> class Matrix_1<T> : public Matrix_base<T> {...};
template<class T> class Matrix_2<T> : public Matrix_base<T> {...};
template<class T> class Matrix_3<T> : public Matrix_base<T> {...};
?
Because by having the second template parameter, one allows for specializations as well as a general, non-specialized implementation. So
Matrix<float, 1000> m;
might do something reasonable but non specialized, whereas you would have to define a Matrix_1000<T>.
Edit: the first point applies in general, but not to this particular case, where the general case has a private constructor.
Furthermore, it allows you to do stuff like
Matrix<double, SOME_CONSTANT> m;
which you cannot do with your _N solution.
Basically the answer is that you can use the template in generic code. You can use a compile time constant to change the behavior of the program, or you can write generic code that will handle different versions of the Matrix class that could not be handled if the types had different names:
template <typename T, int D>
void print( std::ostream& o, Matrix<T,D> const & m ) { ...
That is, even though you need to explicitly create the different types, the specialization mechanism allows you to provide a single name that can be used generically to manage the different types as if they are just variants of one single type.