user17759903
user17759903

Reputation:

Is it possible to make a compile-time evaluated function return a different type than the runtime evaluation of the same function?

Is it possible, at compile time, to determine if a call to a function (a constexpr function mainly) is compile-time evaluated and than just make another version of that function (like what a template does) with a different return type than the original runtime evaluated version ? How ?

constexpr decltype(auto) F(int n)
{
    if consteval
    {
        return (int)3;
    }

    else
    {
        return (char)'c';
    }
}

int main() {
    int n;
    cin >> n;

    cout << typeid(decltype(F(4))).name() << endl;
    cout << typeid(decltype(F(n))).name() << endl;

    return 0;
}

error (gcc 12.2) : "inconsistent deduction for auto return type: 'int' and then 'char'"

Using if constexpr doesn't give this error, because I think it just "deletes" a section of code (if it is false, the "if" section, otherwise the "else" section). But why doesn't if consteval do the same thing ? Is there an other way to do this ?

Upvotes: 0

Views: 136

Answers (1)

Jan Schultke
Jan Schultke

Reputation: 39415

No, it is not possible. consteval if statements (besides their effect on consteval function calls) are essentially equivalent to:

if (std::is_constant_evaluated())   // if consteval
if (!std::is_constant_evaluated())) // if !consteval

The reason why constexpr if statements can influece return type deduction is that they turn the false branch into a discarded statement, making it as if you hadn't written that code at all.

A consteval if statement is simply not going to execute one of the two branches, just like a regular if statement.

Possible Solution

#include <concepts>

struct wrapper {
    int x;
    wrapper(int x) : x(x) {}
};

consteval int f(std::convertible_to<int> auto&&) {
    return 1;
}

// Will lose in overload resolution to the function above
// because the conversion sequence is longer.
char f(wrapper) {
    return char(0);
}

int main() {
    return f(123);
}

With this solution, you have two separate functions, but you call them with the same name because they are overloads of each other. It is a bit more powerful than just using if consteval inside a function though, because any call to f is going to be constant-evaluated if possible, even in cases where it's otherwise not required.

Upvotes: 3

Related Questions