1

I'm able to differentiate constructor of the class and function call operator () overload. However, still it's quite confusing to the user. So, i just wanna get some opinion, maybe from the design perspective, what's a good way to write these code. Using the following simple example which computes the payoff of a call option:

class payoff {
public:
    int strike;
    payoff (int k): strike(k) {}       // constructor which populates the data member strike. 

    int operator()(int s) { return (s > strike) ? s - strike : 0; }     // () overload
};

int main (){
    payoff x(5);
    cout << x(4) << endl;    // output: 2

return 0;
}

When i do payoff x(5), I'm initiate a variable x of type payoff and passing 5 into the constructor. However, when i do x(4), i'm passing 4 as a function argument to do some calculation to get the payoff value. See the ambiguity here? the use of () doesn't seems to be very intuitive.

So I'm just start learning Function object / Functors in c++ and i'm wondering if this is the correct way of designing such a functor? thanks for answering!

Edit: just add some comments on this functor, because a call option will have a fixed 'strike', that's why i think it's appropriate to make it a data member of the class. However, the payoff of the option may vary, depends on the value of stock price 's'. So in the main program i can compute different payoff level with different stock price movement.

Jeremy
  • 379
  • 2
  • 11

2 Answers2

3

So I'm just start learning Function object / Functors in c++ and i'm wondering if this is the correct way of designing such a functor?

I don't know if it is the way, but it is correct and commonly used.

See the ambiguity here?

No! I mean, I see what you mean, but no, I don't see it as an "ambiguity". A slight detour: be careful with the word "ambiguity" as it has a very clear and specific meaning in C++ (and other languages) and it is not what you mean. Anyway, using the word with your meaning, no I don't see the "ambiguity". Any half-decent C++ programmer will have no problem understanding the code you wrote.

And a better way may be to use braced-init-list (better for other reasons):

payoff x{5};
cout << x(4) << endl;

A simpler solution would be to use a lambda:

auto make_payoff_fun(int strike)
{
    return [strike](int s) { return  (s > strike) ? s - strike : 0; };
}


int main (){
    auto x = make_payoff_func(5);
    cout << x(4) << endl;

    return 0;
}

Anyway, back to your ambiguity. You have to look at the context. Yes it's x(5) on both, but one is actually payoff x(5) which, given payoff is a type it is clearly a declaration.

C++ has a context sensitive grammar, which means that it has constructs which you can't know what they are unless you look at the context, aka at code outside the constructs. The language is full of those and are unavoidable:

int *x = &a;
*x = 24;

We have two *x. One is part of a declaration and * is declaring a pointer, the other is an expression and * is the indirection operator.

(foo)(x);

What is the above expression? It depends on what foo and x are. It can be:

  • a call the the function foo with the object x as a parameter:
  • a cast to the type foo of the object x
  • creation of a temporary object of type foo initialized with x.
  • a call to the operator() of the object foo with the object x as parameter.
  • call to the conversion operator (decltype(x))::operator foo()

And I am sure I am missing some.


Do you know what else has a context sensitive grammar? Human language. Here are some examples I hastily found on internet:

Lexical ambiguity:

“I went to the bank.” (The bank could be a place where money is kept, or it could be the edge of a river.”

“I sent the bill to John.” (The bill could be the amount of money John owed or it could be the bill for a cap so John, who repairs caps, can repair one.)

Syntactic (grammatical) ambiguity:

“Visiting relatives can be exhausting.” (What is exhausting: when relatives visit you, or when you visit relatives?)

“Let’s stop controlling people.” (Does this mean ‘Let’s stop people who control others’, or ‘Let’s stop controlling other people?)

bolov
  • 72,283
  • 15
  • 145
  • 224
-3

First, start by adding the explicit keyword to the constructor.

Then, if you want to make the constructor more explicit, you could make it private and then add a public static method create() which returns an instance of that class.

Arne J
  • 415
  • 2
  • 9
  • 1
    How does `explicit` make any difference to OP's question? What good reason is there to use a `create()` method over the constructor? – walnut Nov 20 '19 at 11:25