javaLover
javaLover

Reputation: 6425

pass name of member of PARENT class as template argument

How to pass name of parent's member into template argument?

It is hard to explain, so I will show short code instead.

Example

This code has A derived from Mother. I want to pass name of Mother's field into template of B.

It doesn't compile. I have marked the line that error occurs.

class Mother{
public:
    int motherField=3;   
};

class A: public Mother { 
public:
    int childField=4; 
}; //note: not virtual inherit

template <class T, int T::*a>
class B{ }; 

int main() { 
    B<A,&A::motherField> b;
    //^ could not convert template argument '&Mother::motherField' to 'int A::*'
}

If I change from "motherField" to "childField", it can compile.

It looks like the compiler thinks that Mother::motherField is very different from A::motherField

Question

I want to pass the member of parent, is there anyway to make it compile?

Motivation

B is a special hashMap. Let's name it AMap.

AMap demand that the keys (A) has to dedicate a field (might be int, "motherField" / "childField" in the example) for it, to cache some index.

AMap<A,&A::dedicatedField1> b1;  //I omit the value part for simplicity.
AMap<A,&A::dedicatedField2> b2;
A a1;
b1.cache(a1); //b1 read&write a1.dedicatedField1
b2.cache(a1); //b2 read&write a1.dedicatedField2

This creates a lot of performance benefit.

b1.get(a1);//b1 just read a1.dedicatedField1, then it know where a1 is stored

For convenience, I provide a default dedicatedField in Mother of A, so sometimes I can plug Mother::defaultDedicatedField to the AMap (B).

As a result A.h don't have to contain a dedicated field, so code is cleaner.

Upvotes: 2

Views: 129

Answers (1)

Barry
Barry

Reputation: 302862

Pointers to members have the type of the class that they're actually members of. So even though you write &A::motherField, the type isn't int A::* but is really int Mother::*. The compile error comes from the type mismatch.

You'd have to cast the pointer to member to the type you want:

B<A, static_cast<int A::*>(&A::motherField)> b;

But that doesn't work on either gcc or clang (don't understand why yet), so it may be best to provide a 3rd defaulted type parameter in B instead. You would use that last type to specify a derived class if necessary - like here:

template <class C, int C::*a, class T=C> class B { }; 

B<Mother, &A::motherField, A> b;

Upvotes: 1

Related Questions