C++ Logo

std-discussion

Advanced search

Re: constexpr functions and variables

From: Lénárd Szolnoki <cpp_at_[hidden]>
Date: Thu, 04 Apr 2024 10:54:39 +0100
On Wed, 2024-04-03 at 11:53 +0200, Federico Kircheis via Std-Discussion
wrote:
> Consider following snippet
>
> ----
> // .hpp file
>
> extern const int myconstant;
>
> // .cpp file
>
> constexpr int fun(){return 42;}
>
> constexpr int myconstant = fun();
> ----
>
> It is possible to declare a constant variable in a header file, and
> then
> have it constexpr in the translation unit.
>
>
> This has following advantages:
>
> * no init order fiasco
> * can be used in constexpr context in one translation unit
> * no recompilation of other translation units if value changes
> * does not require to put the "dependencies" for creating
> myconstant
> in the header file
>
>
> I found myself more than once wanting to write something like
>
> ----
> // .hpp file
>
> int function(int);
>
> // .cpp file
>
> constexpr int function(int){return 42;}
> ----
>
> But it is currently not valid C++ (GCC, for example, fails with
> "error:
> redeclaration 'constexpr int function(int)' differs in 'constexpr'
> from
> previous declaration")
>
> I would like to write something like that because it has the same
> advantages of myconstant, except for the init-order-fiasco.
>
>
> A possible workaround is writing
>
>
> ----
> // .hpp file
>
> int function(int);
>
> // .cpp file
> namespace{
> constexpr int function_imp(int){return 42;}
> }
>
> int function(int i){
> return function_imp(i);
> }
> ----
>
> but requires some unnecessary boilerplate code, which cannot even be
> automated with a macro, and it gets error prone with functions that
> accepts multiple parameters.
>
>
> Was such difference between constants and functions considered when
> constexpr did get introduced?
> Or was something similar already proposed?
> I could not find any relevant information.
>
> Best
>
> Federico


I bumped into the same limitations for making dragonbox::to_chars
constexpr, as the main header doesn't include the definition of the
function. I wanted to add a header that does and in turn makes the
function constexpr, so users who want a constexpr to_chars could just
include that header, and other users wouldn't need to pay for
additional compile times. I could indeed make a separate
to_chars_constexpr, but that didn't feel compelling. I might have to go
with that anyway.

Making an expression non-constexpr in one TU and constexpr in an other
could bring interesting ODR challenges, but extern/constexpr variables
already open the way to that. The issues here are much more subtle than
for incomplete types, for better or worse.

Implicit inlineness from constexpr could be the reason why it's hard to
do this for functions. However you can't even do this for function
templates, where inline barely does anything and you can rely on
explicit instantiation declarations/definitions to make sure that the
function body is emitted at least once. I kind of wish that explicit
instantiation declarations/definitions existed for non-template inline
functions as well, and the rules for inline functions were adjusted to
be similar to function templates. Then the rules for adding constexpr
to function declarations could be relaxed.

Modules might make the whole point moot in the long run, but I feel
that headers are here to stay for a long while anyway. And as long as
you support both headers and modules for your library, you still have
to think about interoperability between them.

Cheers,
Lénárd

Received on 2024-04-04 19:06:43