Passing increment/decrement operator to a function
Asked Answered
R

3

5

I have the same function with the only difference that it will either increment or decrement. I would like to generalize from that.

template<typename O>
void f(int& i, O op){
  op(i);
}

int main() {
  int i;
  f(i,operator++);
  f(i,operator--);
  return 0;
}

How can I make this work?

my other option is to use functional std::plus or have two functions but I'd prefer this solution if possible. Thank you.

Rhigolene answered 17/12, 2014 at 21:16 Comment(9)
Just write your own functor. (If you could do this by just writing operator++, there would be no need for std::plus...)Niobic
I don't think you can do that for native types.Christly
f(i,[](int & v) { ++v; });Oppen
@Oppen Wouldn't it be wonderful if we could do f(i, x => x++);Strawboard
@Oppen s/int/auto/, and might also want to return something :)Niobic
@Niobic No on both counts. auto does not compile in C++11 because it does not support generic lambdas. (I do not use C++14 in any examples until it is no longer a draft.) And why would I return anything in this case? The return value of op(i) is not used, so it's pointless to do so.Oppen
@Oppen Well, it's no longer a draft....and the return would be to follow the semantics of the built-in. For this particular use case, it would be superfluous, I agree.Niobic
Can someone explain why I can't use operator++ directly without hacks?Rhigolene
Also, no one mentionned but i'm just using std::plus and modified the code to be i=op(i);. that or lambda is a matter of taste.Rhigolene
U
6

Simply use a lambda:

template<typename O>
void f(int& i, O op){
  op(i);
}

int main() {
  int i;
  f(i,[] (int& x) { ++x; });
  f(i,[] (int& x) { --x; });
  return 0;
}

Also it is not clear whether you want post- or preincrement.

As noted by @T.C. if you want to keep the semantics of the normal operator you can add the return statement.

Unfathomable answered 17/12, 2014 at 21:22 Comment(0)
E
1

Here is one option (there are many possible solutions) that also works pre-C++11:

enum OpType { increment, decrement };

template <OpType op> void f(int &i);
template<> void f<increment>(int &i) { ++i; }
template<> void f<decrement>(int &i) { --i; }

Usage:

f<increment>(i);

To keep your codebase tidy you probably want to use some scoping though, so either use a scoped enum in C++11, or a namespace.

Ers answered 17/12, 2014 at 21:30 Comment(0)
E
1

in the use case you give, typename O is a unary function with no state, which can be modelled with a simple function pointer:

#include <iostream>

int& increment(int& i) {
    ++i;
    return i;
}

int& decrement(int& i) {
    --i;
    return i;
}

template<typename O>
void f(int& i, O op){
    op(i);
}

using namespace std;

int main()
{
    int i = 0;
    f(i, increment);
    cout << i << endl;

    f(i, decrement);
    cout << i << endl;
    return 0;
}

output:

1
0
Excretion answered 18/12, 2014 at 0:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.