my question is about how to template\'ize the name of a class member that should be used.
Maybe a simplified & pseudo example:
sellibitze's solution is fine (though to be honest not very: see my edit), only it limits you to using only members of type int. A more general solution would be this (although the member is NOT a template parameter here)
#include <vector>
struct MyClass
{
int i;
char c;
};
template <class T>
void DoSomething(std::vector<MyClass>& all, T MyClass::* MemPtr)
{
for(std::vector<MyClass>::size_type i = 0; i < all.size(); ++i)
(all[i].*MemPtr)++;
}
int main()
{
std::vector<MyClass> all;
DoSomething(all, &MyClass::i);
DoSomething(all, &MyClass::c);
}
EDIT: Also please note that it is not generally a good idea for a pointer to member to be a template parameter inasmuch as only such pointers that are known compile-time can be passed, that is you can't determine the pointer runtime and then pass it as a template param.
I would use lambdas to solve this problem. Something like this:
#include <vector> // vector
#include <algorithm> // for_each
#include <functional> // function
struct MyClass {
void func1() const { std::cout << __FUNCTION__ << std::endl; }
void func2() const { std::cout << __FUNCTION__ << std::endl; }
};
void doSomething(std::vector<MyClass> all, std::function<void (MyClass& m)> f)
{
std::for_each(all.begin(), all.end(), f);
}
int main()
{
std::vector<MyClass> all;
all.push_back(MyClass());
// apply various methods to each MyClass:
doSomething(all, [](MyClass& m) { m.func1(); });
doSomething(all, [](MyClass& m) { m.func2(); });
}
Of course in this case the function doSomething
is unnecessary. I could just as simply call for_each
directly on all
.
I realize this question is a bit old, but none of the answers use the method I have developed, and I would like to share it.
First, in C++ we typically are discouraged from directly accessing member variables and encouraged to provide setters/getters to help enforce hiding of information.
Second, while C++ goes a long way towards eliminating use of macros, they can still accomplish a lot of things that are difficult (or near impossible) with templates and classes.
The following uses a macro to create typed setters & getters for fields in a container member within a class:
//
// Bit(n) -- sets 'n'th bit.
// Bit(0) == 0x1 (b0000001),
// Bit(1) == 0x2 (b0000010),
// Bit(2) == 0x4 (b0000100),
// Bit(3) == 0x8 (b0001000), etc.
//
#define Bit(n) (1 << (n))
//
// BitMask(n) -- creates mask consisting of 'n' bits.
// BitMask(0) == 0x0 (b00000000),
// BitMask(1) == 0x1 (b00000001),
// BitMask(2) == 0x3 (b00000011),
// BitMask(3) == 0x7 (b00000111), etc.
//
#define BitMask(n) (Bit(n) - 1)
//
// BitRange(n, m) -- creates mask consisting of bits between n & m, inclusive.
// BitRange(0, 3) == 0x0f (b00001111),
// BitRange(2, 5) == 0x3c (b00111100),
// BitRange(6, 1) == 0x7e (b01111110), etc.
//
//
#define BitRange(n,m) (BitMask(n) ^ BitMask(m))
#define namedBitField(name, container, start, end, EnumType) \
EnumType name() const \
{return \
(EnumType) \
((container & BitRange(start,end)) \
>> start); \
}; \
void name(EnumType v) {container |= (v << start);}; \
class myTest
{
public:
enum vSet1
{
a = 1,
b = 2,
};
private:
unsigned long holder;
public:
myTest() {};
namedBitField(set1, holder, 0, 3, vSet1);
namedBitField(set2, holder, 4, 5, vSet1);
};
myTest mt;
The namedBitField() macro takes the name for the getter/setter pair, the target container -- holder in this example, the bitfield start/end, and the EnumType that is to be used for values in the bitfield.
If I now use the setter/getter pairs named set1() & set2() in the above example, and attempt to pass POD (plain-old-data) numbers I will get a warning from the compiler.
mt.set1(22); // compiler warns here.
mt.set1();
mt.set2(myTest::vSet1::a); // no warnings.
mt.set2();
No, it is not a "typed bitfield", but it is the next best thing.
No, it is not quite as easy to use as defining bitfields in a struct, but this way you get strong typing via the setters/getters.
Now, you could define the bitfields in structs, make them private, and access them via setters/getters as well, but then the information about where the bits are located is separated from the setters/getters which logically are tied to that information, and as several responders above have pointed out, each C++ compiler can put the bits anywhere they want, so without looking at generated assembler -- or testing on hardware if you are brave -- you cannot be certain things are happening the way you want.
The way the setters/getters created by namedBitField() manipulate the bits in a well-defined order and guarantee bit-order within container, so you can now use the code cross-platform for accessing I/O registers.
Note: in my example I use 'name' as both setter and getter with compiler sorting it out based on use. Some may prefer 'get_name' and 'set_name'. YMMV.
Since the getters/setters are public, and as long as the things you are iterating all derive from the same base class, you can now iterate across the items in a vector -- as above -- and get type-safe getting/setting for the values used in the iteration.
Template parameters are restricted to types, integer constants, pointers/references to functions or objects with external linkage and member pointers -- but no identifiers.
But you could use a member pointer as template parameter:
template<int MyClass::* MemPtr>
void doSomething(std::vector<MyClass> & all) {
for( i=0; i < all.size(); i++)
(all[i].*MemPtr)++;
}
:
doSomething<&MyClass::aaa>(all);
Note that I changed the doSomething function to take a reference instead of accepting the vector by value.