C++ map a template derived class - c++

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).

Related

Enum inside a templated class

Let's say I have a class Class, which has an associated enum member Enum. The enum only makes sense in the context of this class, and therefore it is specified inside it. Then you can just call Class::Enum::Something from outside of the class, which is fine.
class Class
{
public:
enum class Enum : uchar
{
Something
}
}
However, if the class Class is templated, you cannot do Class::Enum::Something, but you have to Class<T>::Enum::Something (or Class<>::Enum::Something if T has some default type).
template <typename T = double>
class Class
{
public:
enum class Enum : uchar
{
Something
}
}
The Enum has to be the same for all Ts, since it's just a simple enum, but the T always has to be specified anyway.
My question is - is there a clever way of avoiding this?
It is essential to understand that the wrapped enum type is a different type for different specializations of Class.
#include <type_traits>
template <typename T = double>
struct S
{
enum class E : int { a };
};
static_assert(!std::is_same_v<S<>::E, S<int>::E>); // !!!
It seems like you want this to actually be the same type, in which case you could break it out into a separate class and use private implementation inheritance to expose it via the class template specializations:
#include <type_traits>
namespace detail {
struct Base {
enum class E : int { a };
};
} // namespace detail;
template <typename T = double>
struct S : private detail::Base
{
using Base::E;
};
static_assert(std::is_same_v<S<>::E, S<int>::E>); // OK
However if you are set on supplying this enum as a member (alias declaration above) of the various class template specializations, you will need to qualify which specialization you refer to.
S<>::E;
S<int>::E;
The root problem you seem to want to solve is scoping, in which case you may use a namespace instead of class to wrap the associated enum:
namespace my_lib {
template <typename T = double>
struct S {};
enum class E : int { a };
} // namespace my_lib
Often it is more convenient to move everything that does not depend on the tempalte argument to a non-template base class:
#include <iostream>
class Base {
public:
enum class Enum
{
Something
};
};
template <typename T = double>
class Class : public Base
{
};
int main() {
std::cout << (Class<>::Enum::Something == Class<int>::Enum::Something);
}

c++ defining type of a member class without template argument

I am trying to set the type of the member of a class, without passing it through template argument.
In details:
// Forward declaration:
class A;
class B;
class Base
{
};
template <class T>
class Derived : public Base
{
private:
T2 var;
};
where T could be either class A or class B.
What I would like to do is for Derived<A> T2 is int (for instance) and for Derived<B> T2 is double (for instance). I would like to avoid the following solution:
template <class T1, class T2>
class Derived : public Base
{
private:
T2 var;
};
I want to avoid this because for Derived<A> there could be various possible combinations for T2: Derived<A,int>, Derived<A,double>, ...
What I want is that the type of T2 is unique for the entire Derived<A>.
Any idea how to solve that ?
Update: The comments show that the original problem you are trying to solve is not completely explained in the question. I'll leave the original answer nevertheless at the bottom of this answer.
You cannot have two Derived<A> with different types T2 for the var member. In addition, a variable defined by the User can not influence the type of the member variable. Variable values are set at runtime, types are determined at compiletime.
To store a type somehow defined by the user, you will have either have to restrict the variable to a set of known types or use one type that contains a serialized version of the variable's content. The set of known types is often used in the context of databases, where the fields can have one of several predefined types (e.g. String, Integer, Boolean, Double). The type for the member variable then could be a Boost.Variant, restricted to C++ representations of that type. Another application of "user defined types" are where the user of your program has to somehow define the layout and interpretation of the type and its object, for example if your program is the interpreter of some scripting language. In that case again a Boost.Variant (or something similar) can be of use, or, since the value is probably some user provided input, just store the serialized value in a string and interpret it every time you have to deal with it.
Original answer:
This is usually done via template metaprogramming, in this case a type function (sometimes, depending on the context, part of a traits or policy class):
template <class T>
struct DerivedMemVarType {
typedef double type; //default
};
template<>
struct DerivedMemVarType<A> {
typedef int type;
};
And then:
template <class T>
class Derived : public Base
{
typedef typename DerivedMemVarType<T>::type T2;
private:
T2 var;
};
You can also leave out the default, so that any instantiation of Derived for a type that you have not mapped in your function will give a compile error:
template <class T>
struct DerivedMemVarType; //default is not defined
template<>
struct DerivedMemVarType<A> {
typedef int type;
};
template<>
struct DerivedMemVarType<B> {
typedef double type;
};
//...
Derived<C> dc; // ...template error mess....
// --> error: invalid use of incomplete type 'struct DerivedMemVarType<C>'
if you do not have any type specific function call, you can use something like...
class A;
class B;
class Base
{
};
template <class T>
class Derived : public Base
{
public:
Derived(T startVal):var(startVal){}
private:
T var;
};
template <typename T>
Derived<T> MakeDerived(T initValue)
{
return Derived<T>(initValue);
}
and now you can use it the following and the compiler should know what type you are passing to the function.
int initialValue = 0;
auto derived = MakeDerived(initialValue);
I think you can create a separate class that just holds a typedef which you then specialize and use in your Derived class.
template<typename T>
class VarType {
public:
typedef int TheType;
}
template <>
class VarType<B> {
public:
typedef double TheType;
};
template <typename T>
class Derived : public Base {
private:
typename VarType<T>::TheType var;
};

Templated data types with derived classes

Let's say I have the following:
class Base
{
protected:
Base() { }
};
class A : public Base
{
};
class B : public Base
{
};
Now suppose I do this with a template:
TemplatedClass<Base> *generic = new TemplatedClass<A>();
It doesn't work, and I believe I understand why, but I'd like to know if I can do something equivalent. I have several template specializations of the form
typedef TemplatedClass<A> ASpec;
typedef TemplatedClass<B> BSpec;
typedef TemplatedClass<C> CSpec;
I have a single variable whose type I'd like to defer until runtime, so that I can dynamically assign it like
if(condition1)
generic = new ASpec();
else if(condition2)
generic = new BSpec();
Is there any way to go about this? I don't have the ability to change the fact that the classes are templated and not inheriting from a base class, or I'd just do that.
This is not possible in C++.
The fact that A derives from Base doesn't mean that TemplatedClass<A> derives from TemplatedClass<Base>.
See this Stack Overflow post for alternatives:
Conversion from STL vector of subclass to vector of base class
You can derive TemplatedClass<T> from TemplatedClass<Base>, either by specialising if for Base, or by providing a dummy class like this:
struct Dummy {};
template <typename T>
struct BaseClass<T> {
typedef TemplatedClass<Base> Type;
};
template <>
struct BaseClass<Base> {
typedef Dummy Type;
};
template <typename T>
struct TemplatedClass : BaseClass<T>::Type
{
//...
};

Add/Remove data members with template parameters?

Consider the following code :
template<bool AddMembers> class MyClass
{
public:
void myFunction();
template<class = typename std::enable_if<AddMembers>::type> void addedFunction();
protected:
double myVariable;
/* SOMETHING */ addedVariable;
};
In this code, the template parameter AddMembers allow to add a function to the class when it's true. To do that, we use an std::enable_if.
My question is : is the same possible (maybe with a trick) for data members variable ? (in a such way that MyClass<false> will have 1 data member (myVariable) and MyClass<true> will have 2 data members (myVariable and addedVariable) ?
A conditional base class may be used:
struct BaseWithVariable { int addedVariable; };
struct BaseWithoutVariable { };
template <bool AddMembers> class MyClass
: std::conditional<AddMembers, BaseWithVariable, BaseWithoutVariable>::type
{
// etc.
};
First off, your code just won't compile for MyClass<false>. The enable_if trait is useful for deduced arguments, not for class template arguments.
Second, here's how you could control members:
template <bool> struct Members { };
template <> struct Members<true> { int x; };
template <bool B> struct Foo : Members<B>
{
double y;
};

How Best To Implement A Templated Class with Types That Depend On Each Other

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.