I'm playing around with C++ a bit and was trying out templates, enum classes, and such. In my dabbling I encountered an issue that I'm not sure of a good way to solve it. I have two different types of "memory": mem1, and mem2. Both of these have special policies on how to access them but the same methods: create, read, & write. Now, depending on the access type of the memory, I want the compiler to give me an error if, for example, the access type is read-only and its calling write(). Here's what I have so far:
enum class mem1_access_type : int { write = 0, read = 1, rw = 2 };
enum class mem2_access_type : int { write = 3, read = 4, rw = 5 };
struct mem1_access
{
mem1_access() : m(mem1_access_type::rw), p(0);
mem1_access(mem1_access_type _m) : m(_m), p(0);
mem1_access_type getAccess(){ return m; };
int getP(){ return p; };
private:
mem1_access_type m;
int p;
};
struct mem2_access
{
mem2_access() : m(mem2_access_type::rw), p(0);
mem2_access(mem2_access_type _m) : m(_m), p(0);
mem2_access_type getAccess(){ return m; };
int getP(){ return p; };
private:
mem2_access_type m;
int p;
};
template <typename Access>
struct base_policy
{
Access a;
base_policy(Access _a) : a(_a) {};
void create();
//HERE
void write();
//AND HERE
void read();
};
struct mem1_policy : base_policy<mem1_access>
{
mem1_policy(mem1_access _a) : base_policy<mem1_access>(_a) {};
};
struct mem2_policy : base_policy<mem2_access>
{
mem2_policy(mem2_access _a) : base_policy<mem2_access>(_a) {};
};
I was considering using std::enable_if for the write and read methods that checks the access type of the provided access. But I just can't think of how to go about this. What can be used to only compile methods depending on the access_type provided.
EDIT:
Thank you dog jones for your answer! It does exactly what I wanted it to!
Specifically what issues are you encountering when you try to use std::enable_if?
EDIT:
In order to determine if the base_policy class should have create / write / read defined at compile time (using templates), the access type of mem1_access and mem2_access must be compile-time constants:
template <mem1_access_type accessType> struct mem1_access
{
// These typedefs will help 'store' the read/write access information for later:
typedef mem1_access_type AccessType;
typedef std::integral_constant<mem1_access_type, accessType> AccessValue;
mem1_access() : p(0) {}
mem1_access_type getAccess(){ return m; };
int getP(){ return p; };
static const mem1_access_type m = accessType;
private:
int p;
};
template <mem2_access_type accessType> struct mem2_access
{
typedef mem2_access_type AccessType;
typedef std::integral_constant<mem2_access_type, accessType> AccessValue;
mem2_access() : p(0) {}
mem2_access_type getAccess(){ return m; };
int getP(){ return p; };
static const mem2_access_type m = accessType;
private:
int p;
};
Note that you can no longer set the access type in the constructor. It's now a template parameter, a compile time constant. Are you willing to make this trade off?
Later, in base_policy, you can specify default template parameters and then specialize those:
// Be default, this class can write():
template <typename Access, bool shouldWrite=Access::AccessType::write == Access::m || Access::AccessType::rw == Access::m>
struct base_policy
{
Access a;
base_policy(Access _a) : a(_a) {};
void create();
//HERE
void write();
//AND HERE
void read();
};
// This class can't write():
template <typename Access>
struct base_policy<Access, false>
{
Access a;
base_policy(Access _a) : a(_a) {};
void create();
//HERE
//AND HERE
void read();
};
Or use std::enable_if, which I think ought to look something like this (in the body of base_policy):
std::enable_if<Access::AccessType::write == Access::m || Access::AccessType::rw == Access::m, void>::type write();