Here I have functor of the follow kind:
template<class T, class Foo, T Foo::*p>
struct X {
void operator()(Foo & f) {
(f.*p) = 12 * (f.*p); // simple example. could be more complex `operator()`
}
};
And sample struct:
struct FF
{
int m;
int r;
};
I want to use the functor X, but I don't want to explicitly specify template argument as follows:
void testforx()
{
std::vector<FF> cont(5);
std::for_each(cont.begin(), cont.end(), X<int, FF, &FF::r>() ); // it work, but I don't want to write `int` and `FF`
std::for_each(cont.begin(), cont.end(), createx<&FF::r>() ); // how I would like to use it, how to declare `createx` function?
}
Here what I tried with no success:
// that is what I tried, but it could not deduce T and Foo
template<T Foo::*p, class T, class Foo>
X<T, Foo, T Foo::*p> createx()
{
return X<T, Foo, p>();
}
// this works, but requires to write T and Foo explicitly
template<class T, class Foo, T Foo::*p>
X<T, Foo, T Foo::*p> createx()
{
return X<T, Foo, p>();
}
I just wouldn't store the member pointer as a template argument:
template<class T, class Foo>
struct X {
X(T Foo::*p): p(p) {}
void operator()(Foo & f) {
(f.*p) = 12 * (f.*p); // simple example. could be more complex `operator()`
}
private:
T Foo::*p;
};
template <class T, class Foo>
X<T, Foo> MakeX(T Foo::*p)
{
return p;
}
I don't think it is possible to deduce the types with your approach: you can't use a pointer-to-member passed to a function which is where the type deduction occurs.
Edit: There may be macro-based solutions, though.
For example, you can make a class to create X instances, like this:
template <class T, class Foo>
struct XMaker
{
template <T Foo::*p>
X<T, Foo, p> make() { return X<T, Foo, p>(); }
};
Now, you can create a make... function to deduce T and Foo:
template <class T, class Foo>
XMaker<T, Foo> make_x_maker(T Foo::*)
{
return XMaker<T, Foo>();
}
Which makes it possible to write a macro like:
#define CREATE_X(member) make_x_maker(member).make<member>()
Usage:
std::for_each(cont.begin(), cont.end(), CREATE_X(&FF::r) );
I don't think it's possible to reduce the number of template arguments you have to specify if you want an arbitraty member function pointer to be a template argument.
Instead of member function pointers you could use a normal type parameter for a functor that extracts a reference:
template<typename Func>
class X
{
public:
explicit X(Func f = Func()) : f(f) {}
template<class K>
void operator()(K & k) const {
f(k) = 12 * f(k);
}
private:
Func f;
};
Then, you still have the option to use a special functor that directly accesses a certain member (if you think this provides better performance), or use a more general accessor functor that does so with a member function pointer as a member.
I would have one question: do you really need to specify all those arguments ?
struct XR
{
template <class Foo>
void operator()(Foo& foo) const { foo.r = 12 * foo.r; }
};
This works, there is no need for an extra make
method it just works:
void testforx()
{
std::vector<FF> cont(5);
std::for_each(cont.begin(), cont.end(), XR());
}
I prefer not to be TOO generic when I create templates.
If you need to have a more complex operator()
, you can always do some heavy lifting INSIDE it.
Also, you may consider Boost.Bind
, if you really wish to extract pointer functions and references to attributes.
EDIT:
I have an idea, that will be a bit different and does not involve any macro magic, nor even any metaprogramming magic.
Why not simply use a typedef and be done with it ?
Okay, may be not as automated as you wish... but you have only to type this once, after all.
typedef X<int,FF,&FF::m> X_FF_m; // once
std::for_each(cont.begin(), cont.end(), X_FF_m() );
Seems less typing than
std::for_each(cont.begin(), cont.end(), createX<&FF::m>());
repeated over and over.
I barely use naked templates in my code, I prefer to typedef them to improve readability.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With