Add/Remove data members with template parameters? - c++

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;
};

Related

set public/private on template function for some certain template parameter

Is it possible to make a certain template function have 2 accessibility level for some certain template parameter? (via splitting into 2 functions?)
class B{
enum ENU{
T0,T1,T2
}
template<ENU T=T0> someType f(){ ... } //want T1,T2 = public, T0 = private
};
Current usage (the solution should not change it):-
B b;
int aa=b.f<T0>(); //should fail
std::string bb=b.f<T1>();// should ok
Edit: B has a lot of functions like this.
Here is the full code (just in case someone want to edit or use) https://ideone.com/ryNCml.
I doubt what you are trying to do is possible, as specializing functions on a value ain't allowed in C++.
Though if you don't need enumerations, you could write something similar:
class B {
public:
struct T0{};
struct T1{};
struct T2{};
template<typename T> void f(T, ...) {
static_assert(std::is_same_v<T, T1> || std::is_same_v<T, T2>);
}
private:
void f(T0, ...) {}
};
int main(int argc, char **argv) {
B b{};
b.f(T1{}); // Should compile
b.f(T0{}); // Should not compile
}
If you would use the same function implementation, you can either forward this to a common method, or simply put T0 private.
Alternatively, you could make use of a proxy object which could convert the value, though I'm not sure if this is standard C++ of an extension of the compiler I'm familiar with:
class B {
public:
enum class T { //< Strong typed!
T0,
T1,
T2
}
template <T t>
struct TWrapper {};
template <T ActualT>
void f(..., TWrapper<ActualT> tw = TWrapper<ActualT>{});
private:
template <>
struct TWrapper<T0> {};
}
As far as I can understand, you want to forbid the use of T0 as a template parameter while invoking member method f.
To do that, you can use either std::enable_if or a static_assert.
It follows a minimal, working example:
#include<type_traits>
class B {
public:
enum ENU { T0,T1,T2 };
template<ENU T>
std::enable_if_t<(T==T1||T==T2),int>
f() { return 42; }
template<ENU T>
int g(){
static_assert(T==T1||T==T2, "not allowed");
return 42;
}
};
int main() {
B b;
b.f<B::T1>();
// It doesn't work
//b.f<B::T0>();
b.g<B::T1>();
// It doesn't work
//b.g<B::T0>();
}
Given you want to support only a finite set of template arguments, I would write three functions which are not template functions, and give them the right visibility. Then make them delegate to a private template function which does the work. This would look like:
class B{
public:
enum ENU{
T0,T1,T2
}
private:
template<ENU T=T0> int f(){
std::cout<<"In enum "<<T<<std::endl;
return 0;
}
protected:
someType fT0() { return f<T0>(); }
public:
someType fT1() { return f<T1>(); }
someType fT2() { return f<T2>(); }
};
Contrary to your requirements, the usage changes - but this is often the simplest approach:
B b;
int aa=b.fT0(); // fails
int bb=b.fT1();// ok
Alternatively, you can make the template be public, but give it a dummy argument (with a default), and make the type of the dummy argument depend on the template parameter (via traits). If the type of the dummy is a private class, the template will only be callable by a member.
template <ENU T>
struct protection_traits;
class B{
friend class protection_traits<T0>; // So it has access to Protected.
protected:
struct Protected{};
public:
struct Public{};
enum ENU{
T0,T1,T2
}
template<ENU T=T0> int f( typename protection_traits<T>::type = {})
{ std::cout<<"In enum "<<T<<std::endl; }
};
template <ENU T>
struct protection_traits
{
typedef B::Public type; // Default to public
};
template<>
struct protection_traits<T0>
{
typedef B::Protected type; // But T0 uses Protected
};
Usage:
B b;
int aa=b.f<T0>(); // fails (no access to B::Protected)
int bb=b.f<T1>(); // ok
Note: This latter solution hasn't been fed to a compiler. There will be typos.

C++ map a template derived class

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

Templates parametrized for enums

I want to do this:
template <enum Type>
class Message {
private:
Type m_type
};
enum StdInMessages { PrintHello, Echo, ... };
class StdInMsg : Message<StdInMessages>
{ ... }
enum NetworkMessages { DoSomethingElse, Shutdown ... };
class NetworkMsg : Message<NetworkMessages>
{ ... }
Of course, the actual messages are slightly different
Why doesn't this work?
template <enum T> class ATemplate {};
I get this error
error: use of enum ‘T’ without previous declaration
It works if enum T is declared beforehand:
enum T {
foo, bar
};
template <enum T> // or simply `template <T>`
class ATemplate { };
int main() {
ATemplate<foo> x;
}
But judging from the variable name T, this isn’t what you want. Since it’s hard to guess what exactly you want, you need to be more specific.
Because that's not valid syntax for a template unless what you're looking for is what Konrad answered.
You need to either use typename or class.
The following should do it:
enum X
{
a
};
template <typename T> class ATemplate {};
ATemplate<X> A;

Passing a structure as a template-parameter - How can I fix this code?

I'm trying to compile the following code under VC2010.
struct CircValRange
{
double a,b; // range: [a,b)
};
template <struct CircValRange* Range>
class CircVal
{
// todo
};
const CircValRange SignedDegRange= {-180., 180.};
CircVal<SignedDegRange> x;
I'm getting
error C2970: 'CircVal' : template parameter 'Range' : 'SignedDegRange' : an expression involving objects with internal linkage cannot be used as a non-type argument
1> d:\4\circval\circval\circval.h(8) : see declaration of 'CircVal'
1> d:\4\circval\circval\circval.h(13) : see declaration of 'SignedDegRange'
I am trying to define a templated class CircVal that will receive a struct Range as the templated parameter.
I don't want it to be possible to assign classes with one range to classes with another range (I want them to be different types).
How can I do it?
Someone has recommended a constructor parameter, which I second. But you can still do it as originally desired
struct CircValRange
{
double a,b; // range: [a,b)
};
template <CircValRange const& Range>
class CircVal
{
// todo
};
extern const CircValRange SignedDegRange= {-180., 180.};
CircVal<SignedDegRange> x;
But notice that the property that determines the type-identity of CircVal<SignedDegRange> is not the value of SignedDegRange, but the address/identity of it. That is, the following does not work because CircVal<SignedDegRange1> denotes a different type
extern const CircValRange SignedDegRange1 = {-180., 180.};
CircVal<SignedDegRange1> y = x; // error!
As such, an enumeration may be better suited for this
enum RangeKind {
SignedDegRange,
UnsignedDegRange
};
const CircValRange Ranges[] = { { -180., -180. }, { 0., 360. } };
template <RangeKind Range>
class CircVal
{
// todo
};
Or even a traits class with static member functions, similar to a solution someone else had
template <typename Range>
class CircVal
{
// todo
};
struct SignedDegRange {
static double min() { return -180.; }
static double max() { return 180.; }
};
CircVal<SignedDegRange> x;
Instead of making it a template, why don't you reqire a range as a constructor parameter?
struct CircValRange
{
double a,b; // range: [a,b)
};
class CircVal
{
public:
CircVal(const CircValRange &_range) : range(_range) {}
private:
CircValRange range;
// todo
};
const CircValRange SignedDegRange= {-180., 180.};
CircVal x(SignedDegRange);
That way each instance of a CircVal will have an associated range. Then you can override the assignment opearator to prevent assignment with different values.
Or, if you're interested in a different way with templates, you could do something like this for a range:
template <int MIN, int MAX>
class range {
static const int min = MIN, max = MAX;
};
template <class T>
class CircVal {
//todo
};
CircVal< range<10,20> > x;
But of course, that's not very clean or usable.
template <class Range>
class CircVal
{
// todo
};
or
template <class Range> class CircVal;
template<>
class CircVal<CircValRange> {...
to instantiate
CircVal<CircValRange> ...
I think you are omitting one step. If you want to create a template CircVal that you can specialise on a type, you write:
template<typename Range>
class CircVal
{
...
};
and if you then want to specialise it on CircValRange, you create an instance of it as you do further down in your code.
What you seem to try and enforce is that it'll only accept classes derived from a certain base class but unfortunately that's not quite the way templates work - you'll have to find another way to enforce that, maybe by duck typing.

member template specialization and its scope

It appears to me that C++ does not allow member template specialization in any scope other than namespace and global scope (MS VSC++ Error C3412). But to me it makes sense to specialize a base class's primary member template in the derived class because that is what derived classes do - specialize things in the base class. For instance, consider the following example:
struct Base
{
template <class T>
struct Kind
{
typedef T type;
};
};
struct Derived : public Base
{
/* Not Allowed */
using Base::Kind;
template <>
struct Kind <float>
{
typedef double type;
};
};
int main(void)
{
Base::Kind<float>::type f; // float type desired
Derived::Kind<float>::type i; // double type desired but does not work.
}
My question is why isn't it allowed?
I get what you're trying to do, but you are not doing it right. Try this :
struct Base{};
struct Derived{};
// Original definition of Kind
// Will yield an error if Kind is not used properly
template<typename WhatToDo, typename T>
struct Kind
{
};
// definition of Kind for Base selector
template<typename T>
struct Kind<Base, T>
{
typedef T type;
};
// Here is the inheritance you wanted
template<typename T>
struct Kind<Derived, T> : Kind<Base, T>
{
};
// ... and the specialization for float
template<>
struct Kind<Derived, float>
{
typedef double type;
};
My question is why isn't it allowed?
From my copy of the draft it appears that the following puts the above restriction:
In
an explicit specialization declaration for a class template, a member of a class template or a class member
template, the name of the class that is explicitly specialized shall be a simple-template-id.
The workaround is to specialize the enclosing class.
I will "ignore" the standard specifications and try a logical argument:
If you have two classes:
class A
{
struct S { };
};
class B: public A
{
struct S { };
};
A::S and B::S are two different types. Extending the logic to the template specializations, when you try to specialize an inner class declared in base class through an inner class in derived class, you actually are trying to define a different type, with the same name (but another naming scope).