0

EDIT: getPropertySingle and getPropertySingle are class methods of the most base class obj2_t in a hierarchy, different from the most base class obj_t for fAggregate.

This seemed irrelevant (I omitted it as a simplifiction, now added), and the issue posted here on obj_t::*fAggregate seems to be solved by the comment of The Dreams Wind. Now the code compiles. The method is

template<typename retval_t>
const retval_t obj2_t::getProperty(
        const obj_t& obj,
        const retval_t (*fProp)(const vec_t&, const string&, const int),
        const retval_t (obj_t::*fAggregate)(const retval_t&),
        const vec_t& vec,
        const string& s,
        const int i)
{
    const retval_t retval = getPropertySingle<retval_t>(fProp, vec, s, i);
    return obj.*fAggregate(retval);
};

But all target fProp are non-static members of obj2_t. Each specific fProp corresponds with a specific fAggregate, so when specifying on fProp (the reason for templating) there are no more template arguments. An example would be

const int obj2_t::getX(
        const obj_t& obj,
        const vec_t& vec,
        const string& s,
        const int i)
{
    const int retval = getProperty<int>(obj, obj2_t::getXSingle, obj.AggregateX, vec, s, i);
    return retval;
};

This brings compile error invalid use of non-static member function... But this is worth a separate consideration/question.


I have a templated function, obj2_t::getPropertySingle, which takes a function as an argument (I would later write explicit instantiations). In principle, the only reason for templating is simply applying various functions (fProp), each returning a different type retval_t, to the same set of arguments (vec, s, i). I will probably need later on to make it a variadic template.

template<typename retval_t>
const retval_t obj2_t::getPropertySingle(
        const retval_t (*fProp)(const vec_t&, const string&, const int),
        const vec_t& vec,
        const string& s,
        const int i)
{
    return fProp(vec, s, i);
};

Then I have another templated function, whose arguments are: 1) one object (obj) of any class in a hierarchy (obj_t being the most base), 2) one method (fAggregate), which should be present in any of those classes, 3) the same arguments in obj2_t::getPropertySingle so it can be applied.

template<typename retval_t>
const retval_t obj2_t::getProperty(
        const obj_t& obj,
        const retval_t (*fProp)(const vec_t&, const string&, const int),
            1) const string fAggregateStr,        OR
            2) const retval_t (*fAggregate)(const retval_t&),
        const vec_t& vec,
        const string& s,
        const int i)
{
    const retval_t retval = getPropertySingle<retval_t>(fProp, vec, s, i);
    return obj."fAggregateStr"(retval);    <---- HOW TO DO THIS?
};

I mean to pass fAggregate as a string (option 1 above). AFAIK, that is called reflection, and C++ doesn't support it.

Is there any alternative way of achieving this?
I don't know if something like option 2 can be used, because the method fAggregate itself is formed by joining obj and fAggregateStr. I could remove obj from the list of arguments, and pass directly fAggregate as obj."fAggregateStr" from the caller. But that would remove the possibility of combining any obj_t with any "fAggregateStr".

The workaround posted here is quite more complex in my case, if even feasible, like this.

Notes:

  1. I can conceive cases where in requirement 1 above obj_t is not necessarily any in a single hierarchy. In such case one would likely need to template also on that argument.
  2. The requirement 2 is automatically satisfied in my case, since it is a class member for the most base class obj_t. In the case of note 1 above, it wouldn't be automatic.
  • 1
    This cannot be done in C++, like that. C++ does not work this way, on a fundamental level. There are no alternatives or workarounds. Any kind of a solution will involve some kind of a variation of the various approaches you already linked to. – Sam Varshavchik Sep 08 '22 at 11:04
  • 1
    I'm not exactly sure if I understood your final goal (not reflection itself, but essentially what you want to achieve with it), but could you please elaborate why pointer to member functions don't work for you here? [sample code](https://godbolt.org/z/joW5dPvnh) (please igonre `typeReturner` here, it just mimics `getPropertySingle` function and "says" which type to work with) – The Dreams Wind Sep 08 '22 at 11:27
  • AFAIK, there are many reflection libraries in C++, one of which is [rttr](https://github.com/rttrorg/rttr); C++23 will also support static reflection. – o_oTurtle Sep 08 '22 at 12:24
  • @sancho.sReinstateMonicaCellio Okay, sry for my careless browse. Before that, `obj.xxx` seems a member function, and its pointer types seems not like that if it's not static, so I'm a little bit confused. Do you actually mean that you want to call `obj.func`, where `obj` will get any instance of a single specific class and `func` will get one of any functions(with same parameter types and a template type `ret_val`) of that class? – o_oTurtle Sep 08 '22 at 13:41
  • @TheDreamsWind - Your solution at least compiles, that's great! I didn't know about such syntax. A few notes: 1. It is quite worth posting as an answer, so others can vote it and benefit from it. 2. I could prescind of templating on `typename C`. I simply use the most base class. 3. Since my target `fProp`s are class methods, I still could not use `getProperty`. I am getting compile error `invalid use of non-static member function...`. But that is a separate question. – sancho.s ReinstateMonicaCellio Sep 08 '22 at 20:59
  • @SamVarshavchik - The solution by TheDreamsWind seems to work nicely, please see my previous comment. – sancho.s ReinstateMonicaCellio Sep 08 '22 at 21:01
  • @sancho.sReinstateMonicaCellio could you include how the base class looks like in the question? it may give a better idea on how to properly build the code around it. Am I correct to say that it contains all possible overloads of `fAggregateStr` function? – The Dreams Wind Sep 08 '22 at 21:18
  • That solution does not map a string to a function with that name, but takes a completely different approach. – Sam Varshavchik Sep 08 '22 at 23:32
  • @SamVarshavchik - That is correct. In the title I give only one option I imagined as a way to illustrate my real need, but nor a function as a string or a map were mandatory. The body of the OP is the proper space for such explanation, in the title that won't fit. The solution posted ran along the lines of my option 2. It could even have been something different. I guess it *might* help others as well in similar cases. I'm just bringing this to your attention, in case it also helps you better understanding this case. I guess you did know the syntax given, I did not. – sancho.s ReinstateMonicaCellio Sep 09 '22 at 05:37
  • 1
    @sancho.sReinstateMonicaCellio Initially I'm going to answer your question when it's clarified but it seems that it has been solved:); For pointer to member functions, I strongly recommend you to read this [FAQ](https://isocpp.org/wiki/faq/pointers-to-members). – o_oTurtle Sep 09 '22 at 05:58
  • @TheDreamsWind - Please see EDIT, and Notes at the end. Even though I agree that seeing the actual case usually helps, this is part of a huge and intricate code. My base class `obj_t` is itself very large. It would be nearly impossible to reasonably list it here in a useful manner. And I guess you solved that problem anyway, I posted an answer as well. Now I have to deal with passing a non static `fProp` member of another base class `obj2_t`. – sancho.s ReinstateMonicaCellio Sep 09 '22 at 07:38
  • `But all target fProp are non-static members of obj2_t` if these are non-static member functions and assuming `getProperty` is also a non-static member function of `obj2_t`, why not pass it as a pointer to member function (using `obj2_t::*fProp` instead of `*fProp`)? – The Dreams Wind Sep 09 '22 at 07:40
  • @TheDreamsWind - (Pendng comment) `obj_t` does not contain overloads of `fAggregate`. They are methods with different names (representative of what they accomplish), one calling another with various specific values of the parameters. There is a "most generic" method which takes many parameters. There are no overloads and no default parameter values. – sancho.s ReinstateMonicaCellio Sep 09 '22 at 07:43
  • I found this strategy works well for my purposes, I am not sure if there are objective arguments against it, in favor of default parameter values, or if it is simply a matter of taste. – sancho.s ReinstateMonicaCellio Sep 09 '22 at 07:45
  • @TheDreamsWind - Would you mind editing the answer to post the correct syntax for the caller function? All variants I tried produce the same compile error. I added one example, which does not work. – sancho.s ReinstateMonicaCellio Sep 09 '22 at 07:58

1 Answers1

1

The issue on obj_t::*fAggregate seems to be solved by the comment of The Dreams Wind, which templates on obj_t also; not needed here.

Now the code compiles. The method with the proper syntax is

template<typename retval_t>
const retval_t obj2_t::getProperty(
        const obj_t& obj,
        const retval_t (obj2_t::*fProp)(const vec_t&, const string&, const int),
        const retval_t (obj_t::*fAggregate)(const retval_t&) const,
        const vec_t& vec,
        const string& s,
        const int i)
{
    const retval_t retval = getPropertySingle<retval_t>(fProp, vec, s, i);
    return (obj.*fAggregate)(retval);
};

An example caller function would perhaps be

const int obj2_t::getX(
        const obj_t& obj,
        const vec_t& vec,
        const string& s,
        const int i)
{
    const int retval = getProperty<int>(obj, &obj2_t::getXSingle, &obj_t::AggregateX, vec, s, i);
    return retval;
};

Useful example here (for as long as it lasts).

  • To keep discussion in context of the answer, i decided to comment here. The form `T::methodName` is applicable for both, non-static and static member functions (as well as other static members), so when passing a pointer to a non-static member function you also specify this way. Another note - if your `obj` parameter is constant, the member function also must be constant (the `const` qualifier at the end of `fAggregate`, which assumes that the function signature is something like `int func(const int&) const`... – The Dreams Wind Sep 09 '22 at 08:36
  • ...Last but not least, if you want to call a non-static member function in context of the class that owns it from a pointer, you first need to dereference `this`: `(*this.*fProp)()` (it's not part of the sample code, but i assume you will have to make a call to `fProp` at some point inside of `getPropertySingle`) – The Dreams Wind Sep 09 '22 at 08:39
  • [Minimalistic example for the reference](https://godbolt.org/z/5K7dxfMb5) – The Dreams Wind Sep 09 '22 at 08:45
  • 1
    All of your notes and amendments were needed to arrive at a fully working code. In addition to pouring knowledge, you understood right away the exact problem at hand. I should be able to "transfer" the answer to you. It would provide a better picture of the exchange, that is often useful for others who read this. Thanks!! – sancho.s ReinstateMonicaCellio Sep 09 '22 at 10:10
  • [XY questions](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) are difficult to answer, as the question itself often provide context which is not exactly relevant, and that always requires extra investigation. I think OP him(her)self answering such a question is not a rare scenario, because he/she is better aware of the context and the final goal. – The Dreams Wind Sep 09 '22 at 12:12
  • @TheDreamsWind - I found a problem I thought maybe appeared. Since it is separate from this I posted it [here](https://stackoverflow.com/questions/73665298/cannot-convert-unresolved-overloaded-function-type-to). If you can help, I would be glad. – sancho.s ReinstateMonicaCellio Sep 09 '22 at 16:53