# How can I give a C++ lambda expression more than one `operator()`? Raymond

Suppose you have stored a C++ lambda expression into a variable, and you want to call it in different ways. This seems impossible, because when you define the lambda expression, you can provide only one `operator()`:

```auto lambda = [captures](int v) { return v + 2; };
```

This lambda has only one way of calling it: You pass an integer and it returns an integer.

But it turns out that you can create a lambda that can be called in multiple ways: Use an `auto` parameter!

```auto lambda = [](auto p)
{
if constexpr (std::is_same_v<decltype(p), int>) {
return p + 1;
} else {
return "oops";
}
};

auto result1 = lambda(123); // result1 is 124
auto result2 = lambda('x'); // result2 is "oops"
```

By declaring the parameter as `auto`, the lambda accepts any single parameter. We then use `if constexpr` and `std::is_same_v` to see what type was actually passed, and implement the desired function body for each type.

Notice that the different branches of the `if` don’t need to agree on the return type. In our example, passing an integer adds one and produces another integer. But passing anything else returns the string `"oops"`!

You can create a bunch of tag types to make it look almost as if your lambda had member functions.

```struct add_tax_t {};

struct apply_discount_t {};
constexpr apply_discount_t apply_discount;

auto lambda = [total](auto op, auto value) mutable
{
using Op = decltype(op);
total += total * value; // value is the tax rate
} else if constexpr (std::is_same_v<Op, apply_discount_t>) {
total -= std::max(value, total); // value is the discount
} else {
static_assert(!sizeof(Op*), "Don't know what you are asking me to do.");
}
};

lambda(apply_discount, 5.00); // apply \$5 discount
```

So far, all of our “methods” have the same number of parameters, but you can use a parameter pack to permit different numbers of parameters:

```auto lambda = [total](auto op, auto... args) mutable
{
using Op = decltype(op);
using ArgsT = std::tuple<decltype(args)...>;
auto [tax_rate] = ArgsT(args...);
total += total * tax_rate;
} else if constexpr (std::is_same_v<Op, apply_discount_t>) {
auto [amount, expiration] = ArgsT(args...);
if (expiration < now()) {
total -= std::max(amount, total);
}
} else {
static_assert(!sizeof(Op*), "Don't know what you are asking me to do.");
}
};
```

In this case, the `add_tax` “method” takes a single parameter, whereas the `apply_discount` “method” takes two.

You could even dispatch based solely on the types and arity.

```auto lambda = [total](auto... args) mutable
{
using ArgsT = std::tuple<decltype(args)...>;
if constexpr (std::is_same_v<ArgsT, std::tuple<int, int>>) {
// two integers = add to total
auto [a, b] = ArgsT(args...);
total += a + b;
} else if constexpr (std::is_same_v<ArgsT, std::tuple<>>) {
// no parameters = print
print(total);
} else {
static_assert(!sizeof(Op*), "Don't know what you are asking me to do.");
}
};
```

This might come in handy if you have a lambda that is used to accumulate something: You can pass the lambda to the function that expects to do the accumulating, and then call the lambda using a secret knock to extract the answer.

```auto lambda = [limit, total = 0](auto value) mutable
{
using T = decltype(value);
if constexpr (std::is_same_v<T, const char*>) {
} else {
// Otherwise, just add them up until we hit the limit.
total += value;
}
};

auto unused = std::find_if_not(begin, end, std::ref(lambda));
if (unused != end) print("Limit exceeded.");
auto total = lambda("total"); // extract the total
```

This is basically a complete and utter abuse of the language, and I hope you’re ashamed of yourself.

Bonus chatter: All of this is just a way of defining a `struct` without having to say the word `struct`.

```struct
{
double limit;
double total = 0.00;

auto add_tax(auto tax_rate) { total += total * tax_rate; }
auto apply_discount(auto amount) { total -= std::max(amount, total); }
} lambda{1000.00 /* limit */};
```

Bonus bonus chatter: Java anonymous classes provide a more straightforward syntax:

```var lambda = new Object() {
int total = 0;
public void add(int value) { total += value; }
{"ft_lang_label":"__label__en","ft_lang_prob":0.7213116,"math_prob":0.95505947,"size":6922,"snap":"2019-43-2019-47","text_gpt3_token_len":1664,"char_repetition_ratio":0.12648164,"word_repetition_ratio":0.067555554,"special_character_ratio":0.27260908,"punctuation_ratio":0.18248713,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.9975628,"pos_list":[0,1,2,3,4],"im_url_duplicate_count":[null,null,null,null,null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2019-11-20T09:17:08Z\",\"WARC-Record-ID\":\"<urn:uuid:1516b43e-6f2b-486c-b013-6935fd797204>\",\"Content-Length\":\"135943\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:cca8963c-525b-418b-a09b-9bcfb8faa48a>\",\"WARC-Concurrent-To\":\"<urn:uuid:c0b1c265-76cf-4902-a0d9-1148e97a9ba0>\",\"WARC-IP-Address\":\"96.6.59.219\",\"WARC-Target-URI\":\"https://devblogs.microsoft.com/oldnewthing/20191107-00/?p=103071\",\"WARC-Payload-Digest\":\"sha1:BBMFGSHYRX5UINARMKNPF5JG6UJHO3S2\",\"WARC-Block-Digest\":\"sha1:2E56F5IBCPJFXGKLIYYPJ7LNTIDXKSZH\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2019/CC-MAIN-2019-47/CC-MAIN-2019-47_segments_1573496670535.9_warc_CC-MAIN-20191120083921-20191120111921-00553.warc.gz\"}"}