0

Is it possible to invoke the function of a class based on the fact that it is the only public one ? What I mean:

Something like:

double res = MyClass().myFunction(n);

becomes

double res = MyClass()[0](n);

Ideally I would have liked to call the function using a string with its name:

double res = MyClass().reflection("myFunction")(n);

But it seems not possible without wasting at least twice the ink to write the function name (function pointer and corresponding string in a map).

Antonin GAVREL
  • 9,682
  • 8
  • 54
  • 81

2 Answers2

5

You can overload the call operator of the class. This is commonly called a Functor:

class MyClass {
public:
    int operator()(int param) const {
        return functionName(param);
    }

    int functionName(int param) const { return param; }
};

MyClass c;
int returnVal = c(3);

Edit addressing const comment:

The function and operator do not need to be const. You should mark functions const whenever the function does not modify the state of the object. This gives more information to people calling the function and is particularly important in multi-threaded applications. If the function you are calling is not const you can remove the const from the overload.

See this for more info.

Dean Johnson
  • 1,682
  • 7
  • 12
  • 1
    @AntoninGAVREL You can do anything you want in the body of the overloaded operator and you can replace `int param` with any arguments you want. It works just like a function. You can call other functions from there as well. – Dean Johnson Feb 23 '21 at 18:23
  • I trust you but I get ```error: passing ‘const MyClass’ as ‘this’ argument discards qualifiers [-fpermissive] ``` – Antonin GAVREL Feb 23 '21 at 18:25
  • @AntoninGAVREL In your case, you'd need a call operator overload as shown here, which takies a parameter of type `const std::string&`, which is used then to translate to the actual function call (e.g. using a `std::map`. If you need additional (input / output) parameters add them as needed, but you must have a function / operator call signature, which fit's for all the functions you want to call that way. C++ deosn't really support reflection. – πάντα ῥεῖ Feb 23 '21 at 18:26
  • That means that the instance of the class you are calling the operator on is const and you did not mark the operator as const. – Dean Johnson Feb 23 '21 at 18:26
  • @DeanJohnson Consider expanding your example with another one following my comment. That will less confuse the OP, what they can do with the call operator overload (functor). – πάντα ῥεῖ Feb 23 '21 at 18:30
  • OP seems to want to index the methods like `my_class[2]("some value")`. They did mention that there is only one public function, but that makes the whole `[]` syntax unnecessary. So, I am not sure. – Aykhan Hagverdili Feb 23 '21 at 19:11
2

You can get something close to what you wrote by overloading the [] operator:

#include <iostream>
class MyClass
{
public:
  double operator [] (int n)
  {
    return functionName (n);
  }

private:
  double functionName (int n)
  {
    return n + 1;
  }
};


int main ()
{
  int n = 1;
  double res = MyClass ()[n];
  std::cout << "res: " << res << std::endl;
  return 0;
}

See the result here.

Notice tha here, the parameter passed to [] is shown to be of size_t, but I don't think that is a requirement by the standard. I was able to make it work for std::string as well.

#include <iostream>
#include <string>
class MyClass
{
public:
  std::string operator [] (std::string n)
  {
    return functionName (n);
  }

private:
  std::string functionName (std::string n)
  {
    return n + '1';
  }
};

int
main ()
{
  std::string n = "test";
  std::string res = MyClass ()[n];
  std::cout << "res: " << res << std::endl;

}

See here

Ari
  • 7,251
  • 11
  • 40
  • 70
  • very nice as well +1 – Antonin GAVREL Feb 23 '21 at 18:32
  • The array subscript operator used here is often defined with `size_t` as the parameter, but that is just a convention because of what the operator is usually used for (indexing into containers). That is not required by the language standard. – Dean Johnson Feb 23 '21 at 18:44
  • 1
    _@Ari_ _"But interestingly, I was able to make it work even for std::string!"_ Yup! Proven since the very 1st version of `std::map` once was instantiated with the type `std::string` as `KeyType` ;-) And the same for the call operator overload `operator()(const std::string& fnName)` BTW. – πάντα ῥεῖ Feb 23 '21 at 18:44
  • *"the parameter passed to [] should be of size_t"* there is no such requirement. – Aykhan Hagverdili Feb 23 '21 at 19:09