C++ Logo

std-discussion

Advanced search

Separate headers for declaration and constexpr definition of the same function

From: Lénárd Szolnoki <cpp_at_[hidden]>
Date: Fri, 02 Jun 2023 09:24:11 +0100
Hi,

I am trying to come up with a pattern that would allow me to have the
declaration and definition of a constexpr function in separate headers.
The function would need to be explicitly instantiated in a dedicated
translation unit.

One pattern that comes close is the following, however I think it's
technically ill-formed:

square.h:

```
template <typename = void>
constexpr int square(int x);
```

square_constexpr.h:

```
#include "square.h"

template <typename>
constexpr int square(int x) {
  return x*x;
}

extern template int square<>(int);
```

square.cpp:

```
#include "square_constexpr.h"

template int square<>(int);
```

The idea is that users that don't need the constexpr functionality
could include square.h instead of square_constexpr.h , possibly saving
some compile time if square_constexpr.h is much heavier (it could
contain a lot of other additional includes).

Unfortunately doing this with the pattern above is ill-formed, as
constexpr makes the function implicitly inline[1], and inline functions
must be defined in the same TU they are used[2], I see no exemptions
for function templates. Interestingly I merely get a warning in gcc and
clang, and no warning or error on MSVC. According to [2], this should
be strictly ill-formed, not IFNDR.

[1] https://eel.is/c++draft/dcl.constexpr#1.sentence-3
[2] https://eel.is/c++draft/basic.def.odr#12.sentence-2

Compiler explorer: https://godbolt.org/z/3P918PPKq

Some of the questions I have:

1. Is there a pattern for this use case that works according to the
current wording? The headers and the outlined usages should be well-
formed. In particular `square` should resolve to the same function
whether square.h or square_constexpr.h is included, otherwise it
invites for ODR-violation by users who use `square` in the definition
of other inline entities.

2. Should the restriction on inline functions[2] be lifted for function
templates and member functions of class templates? It looks like
compilers already disregard this rule here. It also feels a bit weird
if constexpr/inline has an observable effect on function templates.

Cheers,
Lénárd

Received on 2023-06-02 08:24:15