7

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>();
}
1
  • Small fix (your “correct” code doesn’t compile): your return type declaration of createx should contain p as the third template parameter, not T Foo::*p. Doesn’t change the problem, however. Commented Nov 19, 2009 at 14:02

3 Answers 3

8

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) );
Sign up to request clarification or add additional context in comments.

3 Comments

The question was how to write createx. I already have working compile-time solution and just want to reduce template arguments.
Now this is almost I need. I would accept this answer but I do not like macros.
I think this thread is similar: stackoverflow.com/questions/1447141/…
1

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.

5 Comments

It is allowed by Standard to have member function pointer as template argument.
Yeah, I know. The "I don't think it's possible" refers to the title of the question. I didn't say "member function pointers are not allowed as template parameters". Please read answers more carefully before you downvote. I will try to do my best next time to write answers that cannot be misunderstood. Thanks.
This answer has nothing to do with my question.
@sellibitze. Anyway, your code requires a typename when a pointer to member function is a constant. You should supply a sample how you suppose to use it.
@Alexey: I'm sorry that you think so. @Kirill: I've trouble relating your last comment to my answer. It seems we have a communication problem.
1

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.

2 Comments

It is no option. struct XR use .r-member. If I want use .m member do I need to define a new struct XM? And what about another members?
One structure per member, nothing fancy, just something that works and is simple. Of course in your example you presented a structure with 2 attributes and I would think it scales quite well to 4 or 5...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.