0

I'm working with a map of functions for a simple language I'm developing, everything works fine but I'd like to provide a better way to define the numerical operators which works on numerical values in a more concise way.

The main problem is that I have something like:

using BinaryFunction = std::function<StackValue(StackValue,StackValue)>;

registerFunction("+", Type::FLOAT, {Type::FLOAT, Type::FLOAT}, BinaryFunction([](StackValue v1, StackValue v2) { return StackValue(v1.as<float>() + v2.as<float>()); }));
registerFunction("+", Type::FLOAT, {Type::FLOAT, Type::INT}, BinaryFunction([](StackValue v1, StackValue v2) { return StackValue(v1.as<float>() + v2.as<s32>()); }));
..

So basically for each operator that supports both float and int data types I must provide 4 functions which works with the possible combinations

int, int -> int
int, float -> float
float, int -> float
float, float -> float

Now I don't want to provide implicit type conversion so I'm fine in having 4 different functions for each combination but I'd like a way to define them all at once without having to repeat the code.

The problem is how I could do it, the main problem resides in the lambda:

[](StackValue v1, StackValue v2) { return StackValue(v1.as<float>() + v2.as<float>()); };

To be able to do what I need I'd need a way to parametrize the code with a template, something like

return StackValue(v1.as<T1>() + v2.as<T2>())

Then the correct specialization of StackValue<T>(T) takes care of the rest.

so that I can then do something like

registerNumericFunction(...)
{
  registerTemplate<float, float>(...);
  registerTemplate<s32, float>(...);
  ..
}

But I'm not finding a clever way to do it because I need to pass a lambda to the method which should be parametric. I don't know if it is possible at all.

1
  • @CoffeeandCode: enum Type : u8, that's not a problem since I can use std::conditional to choose the correct one according to the two operator types. Commented Sep 9, 2015 at 15:51

1 Answer 1

2

Do you mean something like this?

template <typename T1, typename T2>
void registerTemplate() {
    registerFunction("+", Type::FLOAT, {Type::FLOAT, Type::FLOAT},
                     BinaryFunction([](StackValue v1, StackValue v2) {
                         return StackValue(v1.as<T1>() + v2.as<T2>());
                     }));
}

registerTemplate<float, float>();
registerTemplate<s32, float>();

Or this?

template <typename T1, typename T2, typename Op>
BinaryFunction makeFunction(Op op) {
    return [op](StackValue v1, StackValue v2) {
        return StackValue(op(v1.as<T1>(), v1.as<T2>()));
    };
}

To be used as:

registerFunction("+", ..., makeFunction<float, float>(std::plus<>{}));
registerFunction("+", ..., makeFunction<s32, float>(std::plus<>{}));

It would really help if you actually make it clear in your question what it is you wanted to accomplish.

Sign up to request clarification or add additional context in comments.

3 Comments

This parametrizes over the type of a specific lambda which is not what I'm looking for, not a generic lambda. The problem is that I have many operators (+, -, *, /, <, >, <=, == and so on) and I'd like to register each operator once but implicitly define it for all the combinations. Basically something like registerTemplate<typename T1, typename T2, typename LAMBDA>
@Jack So pass like std::plus<> in as another argument. I really don't understand what it is you're asking.
indeed I didn't know about std::plus<> and its friends existence, this definitely solves the problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.