I writing an "Effect" class (for an opengl program) and I'm also attempting to write a container class for.
The Effect class is defined as follows:
template <typename T>
class Effect
{
private:
Vbo<T> m_Vbo;
};
Where T is a type that describes the vertex attributes.
In order to write a container class, I'd like to store these effects in an std::map:
class EffectMgr : public Singleton <EffectMgr>
{
private:
typedef std::map<std::string, Effect<T> & > EffectMap;
};
The error I get with the container class is that T is undefined. Can someone enlighten me?
I may have (by sheer chance and tinkering) have found the answer although I won't know until I've written the container class:
class EffectMgr : public Singleton <EffectMgr>,
{
private:
template <typename T>
typedef std::map<std::string, Effect<T> & > EffectMap;
};
T is scoped within the Effect definition. Outside of the scope T is undefined.
Perhaps you mean this?
template <typename T>
class EffectMgr : public Singleton <EffectMgr>
{
private:
typedef std::map<std::string, Effect<T> & > EffectMap;
};
// use: EffectMgr<type>::EffectMap
If you want only the typedef to be templated then do this:
class EffectMgr : public Singleton <EffectMgr>
{
private:
template <typename T>
using EffectMap = std::map<std::string, Effect<T> & >; // C++11 feature
};
// use: EffectMgr::EffectMap<type>
Since Effect is a template class, and you're not specializing it inside EffectMgr, it also needs to be a template:
template<typename T>
class EffectMgr : public Singleton <EffectMgr>
{
private:
typedef std::map<std::string, Effect<T> & > EffectMap;
};
As I understand, you want to store effects with a different T-ypes in a map.
If it is, the simplest way would be specify interface
class IEffect
{
public:
virtual ~IEffect() = 0;
}
IEffect::~IEffect()
{
}
and implement it in your template:
template <typename T>
class Effect: public IEffect
{
private:
Vbo<T> m_Vbo;
};
now, you can create std::map<std::string, IEffect* >
With additional effort, you can write a wrapper over IEffect to get rid of pointers.
Related
Hi I am not sure that this is possible since but I thought of asking since there might be better ways of achieving something similar that I am not aware of.
For simplicity lets just consider that VectorT is
template<class T>
class VectorT: private std::vector<T>`
An attempt to what I wanted to have is something along the lines of.
namespace detail
{
template<class SmartPtr>
class MyClassVectorBase : public VectorT<SmartPtr>
{
public:
MyClassVectorBase() = default;
// all common functions of MyVectorView and MyVector
};
}
using MyClassVectorView = detail::MyClassVectorBase<nonstd::observer_ptr<SomeClass>>;
class MyVector : public detail::MyClassVectorBase<std::unique_ptr<SomeClass>>
{
// only functions related to the actual owner vector
};
What I am hoping is that MyClassVectorBase can be templated only on the smart pointer type and only accept SomeClass.
I thought that it might be possible with a specialization but I got no idea what the syntax for something like that would be
template<class T, class SmartPtr>
class MyClassVectorBase : public VectorT<SmartPtr<T>>
{
};
template<SomeClass T, typename SmartPtr>
class MyClassVectorBase : public VectorT<SmartPtr<T>>
{
};
Is something like that even possible ?
Edited:
Ok let me try to explain this and the logic behind it. I need to have a VectorT of Foo objects. Only Foo and nothing else.
In one case the class will be the owner of the objects and have a few extra functions.
Since it is the owner it will be class MyClassVector : public VectorT<std::unique_ptr<Foo>>
Then I have to somehow operate on these objects but these wont be owned.
The ownership is single and will always outlive the object that I will operate on so no need for shared_ptr.
So Then I guess my class will be a "View class" MyClassVectorView : public VectorT<std::observer_ptr<Foo>>
Instead of observer_ptr it could as well be say raw ptr but the intent is better with it.
Now MyClassVectorView will have all identical functions with MyClassVector which is why I think that I would be inheriting from it.
To do so I need to have a base class that will accept both unique_ptr and observer_ptr.
Then I can avoid duplication so long as I can do MyClassVector : public MyClassVectorView<std::unique_ptr<Foo>>
The alterantive would be have one class and detect with SFINAE if the template parameter is a unique_ptr and then enable the extra functions. This would avoid the extra inheritance.
Not sure about what you want to obtain but I suspect that you need template template parameters.
I suppose you could declare (but not define) MyClassVectorBase as receiving a single template typename parameter
template <typename>
class MyClassVectorBase;
and next define a specialization template-template based; something like
template <template<typename...> class SmartPtr, typename Foo>
class MyClassVectorBase<SmartPtr<Foo>> : public VectorT<SmartPtr<Foo>>
{
public:
MyClassVectorBase() = default;
void doSomething(){}
void doSomething2(){}
};
If Foo isn't a template parameter, but is the Foo struct, you can write
template <template<typename...> class SmartPtr>
class MyClassVectorBase<SmartPtr<Foo>> : public VectorT<SmartPtr<Foo>>
{
public:
MyClassVectorBase() = default;
void doSomething(){}
void doSomething2(){}
};
Your example modified and integrated (with a main() and a dummy observer_ptr)
#include <iostream>
#include <string>
#include <vector>
#include <memory>
namespace nonstd
{
template <typename T>
struct observer_ptr
{ };
}
template <class T>
class VectorT
{
public:
// expose nececssary functions
private :
std::vector<T> container_;
};
struct Foo{
double x;
};
template <typename>
class MyClassVectorBase;
// this class should only accept smart pointers of Foo
template <template<typename...> class SmartPtr, typename Foo>
class MyClassVectorBase<SmartPtr<Foo>> : public VectorT<SmartPtr<Foo>>
{
public:
MyClassVectorBase() = default;
void doSomething(){}
void doSomething2(){}
};
using MyClassVectorView = MyClassVectorBase<nonstd::observer_ptr<Foo>>;
class MyVector : public MyClassVectorBase<std::unique_ptr<Foo>>
{
// function only for this class but still inheriting all MyClassVectorBase stuff
};
int main ()
{
}
I have some class template over std::vector:
template<typename T>
class MyClass{
public:
// public methods;
private:
std::vector<T> buffer_;
// private methods and members
};
This is simplified version of my class. Internal vector here used as a buffer for sorting, different IO operation, relying on its single memory piece implementation such as fstreams custom buffer and buffer size known on runtime only.
All is ok, but vector<bool> instantiation absolutely doesn't suitable for such purpose. I would like to have vector<char> or vector<uint8_t> instead of vector<bool> instantiations in my class. Also I cant use additional libraries like boost, standart library only.
Is there any workaround?
Create a helper class to determine the value type for the vector (this code uses C++11 but can easily be rewritten using only C++98):
template<typename T>
struct VectorValueType {
using type = T;
};
template<>
struct VectorValueType<bool> {
using type = char;
};
template<typename T>
using VectorValueType_t = typename VectorValueType<T>::type;
template<typename T>
class MyClass{
private:
std::vector<VectorValueType_t<T>> buffer_;
};
Use a wrapper subclass like so:
template<typename T>
struct sub_vector: public vector<T> {};
template<>
struct sub_vector<bool>: public vector<char> {};
And then just use that instead of vector.
Use template specialization for the T=bool type.
Then for all types except bool, vector is used.
template <typename T>
class MyClass
{
private:
std::vector<T> buffer_;
};
template <>
class MyClass<bool>
{
private:
std::vector<char> buffer_;
};
You need to specialize every member function that you will add, too.
Hi I have a the following structures and data types:
enum EWorkerType
{
WorkerType1,
WorkerType2,
LastWorker
};
template<class DerivedType>
struct CHandlerMethod
{
};
struct CFunctorA : public CHandlerMethod<CFunctorA>
{
};
struct CFunctorB : public CHandlerMethod<CFunctorB>
{
};
template<class TFunctor>
struct CWorkerHandler
{
CHandlerMethod<TFunctor>* m_HandlerMethod;
};
typedef std::vector<CWorkerHandler<CFunctorA>*> WorkerA;
typedef std::vector<CWorkerHandler<CFunctorB>*> WorkerB;
I need a direction to create a const map between EWorkerType::WorkerType1 to WorkerA and EWorkerType::WorkerType2 to WorkerB.
I tried this direction
struct WorkersMapping
{
WorkersMapping()
{
m_WorkersMapper.insert(EWorkerType::WorkerType2, CFunctorA::value_type());
}
static std::map<EWorkerType, ???> m_WorkersMapper;
};
static WorkersMapping m_WorkersMapping;
You may use something like (for compile time):
template <EWorkerType> struct WorkersMapping;
template <> struct WorkersMapping<WorkerType1>
{
using type = WorkerA;
};
template <> struct WorkersMapping<WorkerType2>
{
using type = WorkerB;
};
or if your enum values is correctly chosen, something like:
template <EWorkerType E> struct WorkersMapping
{
using type = typename std::tuple_element<E, std::tuple<WorkerA, WorkerB>>::type;
};
Wrap WorkerA and WorkerB into respective classes derived from a common base class, in addition to also inheriting from std::vector (multiple inheritance). Then simply define your map value as a smart pointer to the base class (or a regular pointer if you want to put the worker objects on the stack).
As a simplified example, if I have the classes
template <class T, class U> class ProcessEvent
{
public:
ProcessEvent(T* t) : var1(t) { var2 = new U; }
Process() { var2->Process(var1); }
private:
T* var1;
U* var2;
};
class Foo
{
/*data*/
};
class FooProcessor
{
void Process(Foo* foo) {/*functionality*/}
};
class Bar
{
/*data*/
};
class BarProcessor
{
void Process(Bar* bar) {/*functionality*/}
};
So the class ProcessEvent can take have two different sets of template types,
ProcessEvent<Foo, FooProcessor>
ProcessEvent<Bar, BarProcessor>
However, the second template type FooProcessor and BarProcessor are directly implied by the first template type and are implementation details the user doesn't care about. My goal is to have the same functionality as above, but have ProcessEvent take only a single template parameter, Foo or Bar. Other than through specialization of ProcessEvent, can this be done?
I'm going to assume that you simplified for clarity and are reallyusing smart pointers or at least properly managing the memory.
The easiest way to do this is with a typedef in the first class:
class Foo
{
typedef FooProcessor Processor;
// Stuff.
};
Then in your template get rid of U and use typename T::Processor instead.
You can do this as follows:
template<typename T>
class Spec
{
};
template<>
class Spec<Foo>
{
typedef FooProcessor type;
};
template<>
class Spec<Bar>
{
typedef BarProcessor type;
};
Then use Spec<T>::type, with T=Bar or T=Foo, whenever you need BarProcessor and FooProcessor, respectively.
I would assume that a FooProcessor can only process Foo and a BarProcessor can only process Bar, but the other types could have more than one processor class. Thus you could do it intrusively:
class FooProcessor
{
public:
typedef Foo value_type;
};
class BarProcessor
{
public:
typedef Bar value_type;
};
You could use polymorphism:
template< typename T >
class Processor
{
public:
typedef T value_type;
virtual ~Processor() {}
virtual void process( value_type * ) = 0;
};
class FooProcessor : public Processor<Foo>
{
// implement process
};
You could use an adapter class like Matt Phillips's but in reverse, so it takes the process class as template parameter:
template<typename T>
class Spec
{
};
template<> class Spec<FooProcessor>
{
typedef Foo type;
};
template<> class Spec<Bar>
{
typedef BarProcessor type;
};
With intrusive typing and the Spec adapter typing your ProcessEvent template would take the processor type as parameter and derive the other one using value_type or type.
With polymorphism, your ProcessEvent would take the object type as parameter (Foo or Bar) and would be passed a processor that derives from Processor or Processor to process events.
If there are huge numbers of events to process and it is always processing them with the same object, the latter method would of course be slightly less efficient as it is processing through a v-table. It depends partly how long they take to process and whether the function that does it could be inlined.
Can anyone explain why this code gives the error:
error C2039: 'RT' : is not a member of 'ConcreteTable'
(at least when compiled with VS2008 SP1)
class Record
{
};
template <class T>
class Table
{
public:
typedef typename T::RT Zot; // << error occurs here
};
class ConcreteTable : public Table<ConcreteTable>
{
public:
typedef Record RT;
};
What can be done to fix it up. Thanks!
Update:
Thanks pointing out the issue, and for all the suggestions. This snippet was based on code that was providing an extensibility point within an existing code base, and the primary design goal was reducing the amount of work (typing) required to add new extensions using this mechanism.
A separate 'type traits' style class actually fits into the solution best. Especially as I could even wrap it in a C style macro if the style police aren't looking!
That's because the class ConcreteTable is not yet instantiated when instantiating Table, so the compiler doesn't see T::RT yet. I'm not really sure how exactly C++ standard handles this kind of recursion (I suspect it's undefined), but it doesn't work how you'd expect (and this is probably good, otherwise things would be much more complicated - you could express a logical paradox with it - like a const bool which is false iff it is true).
Fixing
With typedefs, I think you cannot hope for more than passing RT as additional template parameter, like this
template <class T, class RT>
class Table
{
public:
typedef typename RT Zot;
};
class ConcreteTable : public Table<ConcreteTable, Record>
{
public:
typedef Record RT;
};
If you don't insist on RT being available as Table<>::Zot, you can put it inside a nested struct
template <class T>
class Table
{
public:
struct S {
typedef typename RT Zot;
};
};
class ConcreteTable : public Table<ConcreteTable>
{
public:
typedef Record RT;
};
Or even external traits struct
template <class T>
struct TableTraits<T>;
template <class T>
struct TableTraits<Table<T> > {
typedef typename T::RT Zot;
};
If you only want the type be argument/return type of a method, you can do it by templatizing this method, eg.
void f(typename T::RT*); // this won't work
template <class U>
void f(U*); // this will
The point of all these manipulations is to postpone the need for T::RT as late as possible, particularly till after ConcreteTable is a complete class.
Why not just do something like this?
class Record
{
};
template <class T>
class Table
{
public:
typedef typename T Zot;
};
class ConcreteTable : public Table<Record>
{
public:
typedef Record RT; //You may not even need this line any more
};
The problem is that ConcreteTable is defined in terms of Table, but you can't define Table without a definition of ConcreteTable, so you've created a circular definition.
It also looks like there may be an underlying problem in the way you are designing your class hierarchy. I am guessing what you are trying to do is provide ways of manipulating a generic record type in your definition of Table, but leaving it up to ConcreteTable to define what the record type is. A better solution would be to make the record type a parameter of the Table template, and ConcreteTable a direct subclass:
class Record {};
template <class T>
class Table {
public:
typedef T RT;
};
class ConcreteTable : public Table<Record> {
};
Now you eliminate the circular dependency, and Table is still abstracted based on the type of record.
Notice that what you want to do can't be allowed by the compiler. If it was possible, you would be able to do this:
template <class T>
class Table
{
public:
typedef typename T::RT Zot;
};
class ConcreteTable : public Table<ConcreteTable>
{
public:
typedef Zot RT;
};
Which would be a kind of type-definition-infinite-loop.
The compiler blocks this possibility by requiring a class to be fully defined when one of its members needs to be used; in this case, the point of template instatiation for Table (the ancestors list in ConcreteTable) is before the definition of RT, so RT can't be used inside Table.
The workaround requires having an intermediate class to avoid the mutual dependence, as others already stated.
When Table<ConcreteTable> is instantiated, ConcreteTable is still an incomplete type. Assuming you want to stick with CRTP you could just pass Record as an additional template parameter like:
class Record
{
};
template <class T, class U>
struct Table
{
typedef U RT;
};
struct ConcreteTable : Table<ConcreteTable, Record>
{
};
Also note that you can access ConcreteTable as a complete type in any member functions in Table because they are instantiated only later when used. So this would be ok:
struct Record
{
};
template <class T>
struct Table
{
void foo()
{
typedef typename T::RT Zot;
Zot a; // ...
}
};
struct ConcreteTable : Table<ConcreteTable>
{
typedef Record RT;
};
int main()
{
ConcreteTable tab;
tab.foo();
}
I think everyone else has covered it pretty well, I just wanted to add that I think it's bad practice to inherit from a template of self and then try to patch things round to make it work. I would take a different approach and have the record type (RT) as the parameters instead of ConcreteTable itself. If you've ever looked at the std::iterator class, it uses this exact approach:
template <class Category, class T, class Distance = ptrdiff_t,
class Pointer = T*, class Reference = T&>
struct iterator {
typedef T value_type;
typedef Distance difference_type;
typedef Pointer pointer;
typedef Reference reference;
typedef Category iterator_category;
};
When a subclass inherits from iterator, it does this:
struct ExampleIterator : std::iterator<std::forward_iterator_tag, Example>
Which is exactly what you want to do. Notice that the 'RecordType' fields are actually in the superclass, and passed in through template parameters. This is the best way to do it, it's in the standard library because of it.
If you want to do more specialisation of the ConcreteTable subclass, you can always override methods from Table, as well as using the template parameters.
you are trying to use class CponcreateTable as a template parameter before the class is fully defined.
The following equivalent code would work just fine:
class Record
{
};
template <class T> Table
{
public:
typedef typename T::RT Zot; // << error occurs here
};
class ConcreteTableParent
{
public:
typedef Record RT;
};
class ConcreteTable: public Table<ConcreteTableParent>
{
public:
...
};