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
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