4

Currently I am doing:

if constexpr(constexpr_bool_var1) {
    auto arg1 = costly_arg1(); auto arg2 = costly_arg2();
    if (costly_runtime_function(arg1, arg2)) {
        // do X, possibly more constexpr conditions
        // do Y
        // ...
    }
} else {
    // do X, possibly more constexpr conditions
    // do Y
    // ...
}

One possible way is to convert the do X/Y etc. to one function doXY() and call it in both places, however it seems very unwieldy, as I have to write a function that solely exists for convenience of meta programming.

What I want is something like:

if not constexpr(constexpr_bool_var1 && some_magic(costly_runtime_function(arg1, arg2)) {
  // do X, do Y
} 

Another way is:

auto arg1 = costly_arg1(); // Unneeded extra work out not within constexpr
auto arg2 = costly_arg2();
if (constexpr_bool_var1 && costly_runtime_function(arg1, arg2)) {
} else {
    // do X, possibly more constexpr conditions
    // do Y
    // ...
}

However here arg1 and arg2 are being declared outside the if condition so they will be needlessly instantiated.

5
  • 1
    What about a lambda outside the if? auto doXY = [] { doX(); doY(); }; and then call it in both places. Commented Oct 13, 2017 at 3:59
  • 3
    Since if constexpr requires the test to be done at compile time, and the result of costly_runtime_function() will be unknown until run time, it can't be used in if constexpr. Commented Oct 13, 2017 at 4:06
  • 2
    If I understand correctly, you want to do X and Y no matter what if constexpr_bool_var1 is false, and maybe if it's true but you won't know until runtime? In that case, can't you just do bool do_x_y = true; if constexpr (constexpr_bool_var1) { do_x_y = costly_runtime_function(/* ... */); } if (do_x_y) { /* ... */ }? Commented Oct 13, 2017 at 5:48
  • @DanielH - I think you should present your comment as an answer (a good answer, IMHO). Commented Oct 13, 2017 at 9:34
  • 1
    don't forget that if a value is evaluated at compile-time, condition like if (constexpr_val && runtime_val) is optimized into if (runtime_val) anyway. if constexpr is mostly meant to be used when suppressed branch cannot be compiled. Commented Oct 13, 2017 at 9:36

3 Answers 3

3

I’m not sure I understand your question correctly; your original code and your second alternative don’t express quite the same function (the meaning of costly_runtime_function is reversed from “do X and Y” to “don’t do X and Y”), and in your first propoed alternative I don’t understand what your proposed syntax or what some_magic is. I’m answering your question with the semantics of your original code sample.

The best way to handle this is probably with a flag for whether or not to do X and Y:

bool do_x_y = true;
if constexpr(constexpr_bool_var1) {
    // Maybe we don't actually want X and Y
    auto arg1 = costly_arg1(); auto arg2 = costly_arg2();
    do_x_y = costly_runtime_function(arg1, arg2);
}
if (do_x_y)  {
    // do X, possibly more constexpr conditions
    // do Y
    // ...
}

Note that, as Andrei R. points out in the comments, the compiler can probably handle the optimization anyway. This makes it clearer to a human reader that you want this handled at compile time, though.

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

1 Comment

Thank you, I think this should work and is clear to the reader also.
0

Here's one way. Whether it's more expressive/maintainable I cannot say.

#include <cstdlib>
#include <utility>

/*
 * simulation
 */
void doX() {}
void doY() {}

int costly_arg1() { return 1; }
int costly_arg2() { return 2; }

bool costly_runtime_function(int, int) { return rand() < RAND_MAX / 2; }

constexpr bool constexpr_bool_var1 = true;

/*
 * A functor that maybe does something
 */
template<class F>
struct maybe_do
{
    constexpr maybe_do(F&& f) : f(std::move(f)) {}

    constexpr void operator()() const 
    {
        if (enabled)
            f();
    }

    constexpr void enable(bool e) {
        enabled = e;
    } 

    F f;
    bool enabled = true;
};

int main()
{
    auto thing = maybe_do{
        [] {
            doX();
            doY();
        }
    };

    if constexpr(constexpr_bool_var1) 
    {
        thing.enable(costly_runtime_function(costly_arg1(), 
                                             costly_arg2()));
    }
    thing();
}

3 Comments

The OP didn’t want to make a doXY function because it seemed like too much extra code just for this one case, so you propose a lot more boilerplate instead? Either way, you have a bug; thing starts out enabled and you never disable it anywhere.
@DanielH thing is disabled if you call thing.enable(false);
Oh, I see. I still think that’s far too much boilerplate if even extracting X and Y into their own function is too much, but but it looks like it’ll work.
0

You could use a lambda for that:

auto stuff = [&] {
    // do X, possibly more constexpr conditions
    // do Y
    // ...
};

if constexpr(constexpr_bool_var1) {
    auto arg1 = costly_arg1(); auto arg2 = costly_arg2();
    if (costly_runtime_function(arg1, arg2)) {
        stuff();
    }
} else {
    stuff();
}

And if your lambda can receive auto values, you could also pass variable of different types from inside the if scope.

Comments

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.