How to Declare Constexpr Class in a Header and Define It in a Separate .Cpp File

Is it possible to declare constexpr class in a header and define it in a separate .cpp file?

If a constexpr function is not defined inside the header, the compiler can not see the definition of the constexpr functions while compiling all the other source files.

Obviously, if it can't see the definition of the functions, it can't perform the steps necessary to calculate them at compile-time. Thus all constexpr functions must be defined everywhere they are used.

Thanks @IgorTandetnik:

[dcl.constexpr] §7.1.5/2

constexpr functions and constexpr constructors are implicitly inline.

[basic.def.odr] §3.2/4

An inline function shall be defined in every translation unit in which it is odr-used.

C++17: Defining static constexpr member functons in .cpp file

I would like learn if there is a way to define a static constexpr member function in the .cpp file rather than the header.

Yes... but you must define the function in every TU where it is used because it is an inline function. As such, it is simpler to put the definition into a header so that same definition will be included into all the TUs that need it.

It is an inline function because constexpr functions are implicitly inline functions - i.e. whether or not you use the inline keyword.

is there any side effects defining the function in the .h file ?

The effect of doing this is that the function definition will be included into every TU that include the header. I don't quite understand what you mean by "side" effect in this context.

Forward declaring a constexpr function in a header

It's wrong. constexpr implies that the function is inline. Inline functions must be defined in every translation unit where it's used. If you include that header in a translation unit other than source.cpp and use the function, that translation unit lacks the definition.

So, the solution is to move the implementation to the header. No need to worry about multiple definition, since the function is inline.

It doesn't technically need to be in the same file, but because the definition must be in every file that uses the function, it's simplest to define it in the same header.

Constexpr constructor defined in .cpp file causes linking error

The function is implicitly an inline function. It should be defined in any compilation unit that calls it.

From the c++17 Standard (10.1.5 The constexpr specifier)

1 The constexpr specifier shall be applied only to the definition of a
variable or variable template or the declaration of a function or
function template. A function or static data member declared with
the constexpr specifier is implicitly an inline function or
variable
...

How to declare constant parameters in separate class or header file in C++?

Why do you feel that you need a class for this? That doesn't seem appropriate. FORTRAN comparisons are also not likely to bear much fruit as C++ is a different language with different idioms and concepts.

To me, it seems like you should simply put those constants in a header file. Be sure to make them static const constexpr to avoid linker clashes.

// Constants.hpp
#ifndef MYLIB_CONSTANTS_HPP
#define MYLIB_CONSTANTS_HPP
#pragma once

static constexpr const int Number_0 = 234;
static constexpr const float Number_1 = 34.76;
static constexpr const double Number_2 = 98.78;

#endif

Now you just #include "Constants.hpp" in any translation unit that requires access to these values.

For the record, the old-school C approach to do the same thing would be to use #defines.

Don't forget to give these constants meaningful names.

Initialize static float constexpr member in the definition (.cpp file) is it possible

With static constexpr members you cannot leave off the initializer in the class definition. A constexpr variable must be initialized when declared because it can be used after it is declared in a constant expression. This is detailed in [class.static.data]/3 of the C++11 standard

If a non-volatile const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression ([expr.const]). A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. — end note ] The member shall still be defined in a namespace scope if it is odr-used ([basic.def.odr]) in the program and the namespace scope definition shall not contain an initializer.

emphasis mine

So, with that, your code needs to be

// .h file
class Shape {
public:
virtual void getArea();

private:
static constexpr float pi = 3.14; // we initialize here so it can be used.
};

// .cpp file
constexpr float Shape::pi; // we define here so it can be odr-used

Do note that this has changed in C++17. With the introduction of inline variables static constexpr member variables no longer need to be defined outside of the class. The compiler will handle it for you and ensure only a single defentition of the object exists. You can still define the member if you want, but that ability is deprecated and will most likely be removed in a future standard revision. The new text for [class.static.data]/3 is

If a non-volatile non-inline const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression ([expr.const]). The member shall still be defined in a namespace scope if it is odr-used ([basic.def.odr]) in the program and the namespace scope definition shall not contain an initializer. An inline static data member may be defined in the class definition and may specify a brace-or-equal-initializer. If the member is declared with the constexpr specifier, it may be redeclared in namespace scope with no initializer (this usage is deprecated; see [depr.static.constexpr]). Declarations of other static data members shall not specify a brace-or-equal-initializer.

emphasis mine

and [dcl.constexpr]/1 says that a static constexpr variable is implicitly inline

The constexpr specifier shall be applied only to the definition of a variable or variable template or the declaration of a function or function template. The consteval specifier shall be applied only to the declaration of a function or function template. A function or static data member declared with the constexpr or consteval specifier is implicitly an inline function or variable ([dcl.inline]). If any declaration of a function or function template has a constexpr or consteval specifier, then all its declarations shall contain the same specifier.

emphasis mine

Is there a way to avoid constexpr function used in header file from entering global scope without extra namespace for it?

There's no way to "undeclare" a function or variable in C++ (header file or not -- a header file is just included into the current translation unit). You'll need to use a namespace, or make GenTag into a macro. You can undefine macros with #undef MACRONAME.



Related Topics



Leave a reply



Submit