Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Idiomatic way to enforce constexpr-ness of constexpr functions

Consider the following example code :

#include <tuple>
void blah();
int buh;

constexpr auto get() 
{ 
    return std::get<0>(std::make_tuple(&blah, &buh));
}

int main()
{
    get();
}

One would expect that since the function get() is a constant-expression, it would return a constant.

That's not what happens: std::make_tuple, std::get are instantiated and called: https://godbolt.org/g/PkHrTp

Now, if we replace the implementation of get() by

constexpr auto get() 
{ 
    constexpr auto x = std::get<0>(std::make_tuple(&blah, &buh));
    return x;
}

We get the expected behaviour : the parameter x's computation is optimized out, even at -O0, and make_tuple, get are not instantiated, which can be fairly useful to reduce binary bloat.

Is there an idiomatic way to enforce that functions of the form constexpr auto foo() always behave like in the second example ?

For now I would resort to :

#define constexpr_return(X) do { constexpr auto constexpr_return_x_ = X; return constexpr_return_x_; } while(0)

constexpr_return(std::get<0>(std::make_tuple(&blah, &buh)));

for instance but I don't know if this is optimal.

like image 673
Jean-Michaël Celerier Avatar asked May 24 '18 21:05

Jean-Michaël Celerier


People also ask

What are constexpr functions?

A constexpr function is one whose return value is computable at compile time when consuming code requires it. Consuming code requires the return value at compile time to initialize a constexpr variable, or to provide a non-type template argument.

How do I know if a function is constexpr?

The easiest way to check whether a function (e.g., foo ) is constexpr is to assign its return value to a constexpr as below: constexpr auto i = foo(); if the returned value is not constexpr compilation will fail.

Why constexpr instead of define?

#define directives create macro substitution, while constexpr variables are special type of variables. They literally have nothing in common beside the fact that before constexpr (or even const ) variables were available, macros were sometimes used when currently constexpr variable can be used.

Can you modify constexpr?

A const int var can be dynamically set to a value at runtime and once it is set to that value, it can no longer be changed. A constexpr int var cannot be dynamically set at runtime, but rather, at compile time. And once it is set to that value, it can no longer be changed.


1 Answers

template<auto x>
std::integral_constant< std::decay_t<decltype(x)>, x > k{};

non-type template parameters must practically be evaluated at compile time.

k<get()> or in certain corner cases k<get()>() probably does what you want.

This doesn't work for constexpr values that cannot be passed as non-type template parameters, but it does work for integers and pointers and function pointers.

like image 169
Yakk - Adam Nevraumont Avatar answered Oct 03 '22 04:10

Yakk - Adam Nevraumont