Constexpr class function definition linking error [duplicate] - c++

This question already has answers here:
C++17: Defining static constexpr member functons in .cpp file
(1 answer)
Is it possible to declare constexpr class in a header and define it in a separate .cpp file?
(2 answers)
Undefined symbols for constexpr function
(3 answers)
Closed 5 months ago.
Function is declared in hpp file like this:
class StringProcessor
{
static constexpr const char* string_process(const char* initial_string, std::size_t string_length, const char* key, std::size_t key_length);
};
And defined in cpp like this:
constexpr const char* StringProcessor:: string_process(const char* initial_string, std::size_t string_length, const char* key, std::size_t key_length)
{
...
}
How do I call it, because following line throws Undefined symbols for architecture x86_64: "StringProcessor::string_process(char const*, unsigned long, char const*, unsigned long)", referenced from: _main in main.cpp.o error:
std::cout << StringProcessor::string_process("Test", 4, "Test", 4) << std::endl;

constexpr functions are implicitly inline and therefore need to be defined in every translation unit where they are used. That usually means that the definition should go into a header shared between the translation units using the function.
Also, in order for constexpr to be of any use, the function needs to be defined before its potential use in a constant expression. Therefore it usually only really makes sense to define it directly on the first declaration, i.e. here in the class definition in the header.

Related

LLVM C++ : compiler fail to identify primitive type of class member as const [duplicate]

This question already has answers here:
Static constant string (class member)
(11 answers)
Why can't I have a non-integral static const member in a class?
(5 answers)
Why must non-integral static data members initialized in the class be constexpr?
(3 answers)
Closed 2 years ago.
Consider the following class in which I define 2 static variables with constant value and initialisation upon declaration.
Both variable are primitive, but for the string initialisation I get the following error when compiling with LLVM (clang) Non-const static data member must be initialized out of line even though its type is preceded by const. In visual studio, the same code passed compilation.
perhaps anybody can explain this discrepancy ?
class my class
{
public:
// the variable in this line is recognised as non-const.
// Therefore, it doesn't allow initialisation.
static const wchar_t* bla = L"000111";
// this line compiles perfectly well.
static const int bla2 = 128;
}

How to declare constexpr c-string member? [duplicate]

This question already has answers here:
Undefined reference to static variable c++
(3 answers)
Undefined reference to static constexpr char[]
(6 answers)
Closed 3 years ago.
How to declare constexpr c-string member ? Non-member constexpr c-string can be declared this way:
constexpr char id_[] = "aaa";
so I have though that I can declare it this way:
struct T
{
const static constexpr char id_[] = "aaa";
};
but I get undefined reference error.

Static constexpr members seem not to go along with std::min [duplicate]

This question already has an answer here:
Why does constexpr static member (of type class) require a definition?
(1 answer)
Closed 7 years ago.
Here is a problem the reason of which is quite obscure to me, but the workaround of which is fortunately quite easy.
Consider the following code (let me call it my main.cpp):
#include <algorithm>
struct Foo {
static constexpr float BAR = .42;
float operator()() const noexcept {
float zero = .0;
return std::min(zero, BAR);
}
};
int main() {
Foo foo;
foo();
}
When I tried to compile it, I got the error:
foobar:~/stackoverflow$ g++ -std=c++11 main.cpp
/tmp/ccjULTPy.o: In function 'Foo::operator()() const':
main.cpp:(.text._ZNK3FooclEv[_ZNK3FooclEv]+0x1a): undefined reference to `Foo::BAR'
collect2: error: ld returned 1 exit status
The same happens (quite obviously) also if I use the following statement:
return std::min(zero, Foo::BAR);
Below a slightly modified version of the example above.
This one compiles with no error, even though I'm still referring to the BAR member:
#include <algorithm>
struct Foo {
static constexpr float BAR = .42;
float operator()() const noexcept {
float zero = .0;
float bar = BAR;
return std::min(zero, bar);
}
};
int main() {
Foo foo;
foo();
}
I didn't succeed in understanding why the latter version compiles fine while the former ends with an error.
As far as I know, both the versions are correct and should compile, but I strongly suspect that I'm missing something important here.
Any suggestion?
Here my compiler's version: g++ (Debian 5.3.1-5) 5.3.1 20160101.
The selected prototype for min is
template<class T>
/* constexpr since C++14 */ const T& min( const T& a, const T& b );
The pertinent point is that it takes the argument by reference, meaning it One-Definition-Rule (ODR)-uses it.
And you never defined it, you only declared it in your class (with an initializer):
static constexpr float BAR = .42;
Which is good enough for copying and otherwise using the value, but not for using it as anything but a prvalue.
See Why does constexpr static member (of type class) require a definition?
Violation of the ODR (whose finer points are fine and voluminuous indeed) need not be diagnosed:
3.2 One definition rule [basic.def.odr]
4 Every program shall contain exactly one definition of every non-inline function or variable that is odr-used
in that program; no diagnostic required. The definition can appear explicitly in the program, it can be found
in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see 12.1, 12.4 and
12.8). An inline function shall be defined in every translation unit in which it is odr-used.

Strange error C2131: expression did not evaluate to a constant in VC 2015

// foo.hpp file
class foo
{
public:
static const int nmConst;
int arr[nmConst]; // line 7
};
// foo.cpp file
const int foo::nmConst= 5;
Compiler VC 2015 return error:
1>foo.h(7): error C2131: expression did not evaluate to a constant
1> 1>foo.h(7): failure was caused by non-constant arguments or
reference to a non-constant symbol 1> 1>foo.h(7): note: see usage of
'nmConst'
Why? nmConst is static constant with value defined in *.cpp file.
It's possible to use static const int member as an array size, but you'll have to define this member within class in your .hpp file like so:
class foo
{
public:
static const int nmConst = 10;
int arr[nmConst];
};
This will work.
P.S. About the logic behind it, I believe compiler wants to know size of the array member as soon as it encounters class declaration. If you leave static const int member undefined within the class, compiler will understand that you're trying to define variable-length array and report an error (it won't wait to see if you actually defined nmconst someplace).

Linker gives error "undefined symbol" for integral static const members used in certain contexts [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C++ - defining static const integer members in class definition
Note: There are several extant questions re similar issues, but I have reviewed many of them and cannot find an answer that explains this behavior:
Say I have code such as the following (in a header file)
class Foo {
static const int TEST = 33;
public:
void willItWork(void) {
printf("%d", std::max(TEST, 75)); // embedded platform, no streams
}
};
int main(void) {
Foo tester;
tester.willItWork();
}
This will compile, but it will not link. I get the linker error
Error: L6218E: Undefined symbol Foo::TEST (referred from foo.o).
It only seems like passing the value to outside functions causes problems. Using TEST in ordinary expressions or functions within the class works fine. If I instead write willItWork() as
void willItWork(void) {
int diff = TEST - 23;
printf("%d", diff);
}
there is no error.
I found another question that referenced the C++ standard regarding this (Section 9.4.2):
If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a const-initializer which shall be an integral constant expression.
Since what I have done seems to be "within the rules," can anyone think of any possible explanation for this odd behavior?
I tried similar code on ideone and had no issue (however, I can not mimic the exact structure, i.e. with header files, there). Does this mean the linker I am using doesn't quite conform to the standard here?
Any insight is greatly appreciated. I can always provide more information, too.
If the compiler feels it needs the address of the static member variable, e.g., when binding the variable to a reference at some point, it will create a corresponding undefined symbol and you will have to define the member:
int const foo::TEST;
(in one translation unit). If the compiler only ever accesses a the value you can get away with not defining the object. Unless you need the type to be an int, you can use an enum instead and avoid the need for defining the member:
enum { TEST = 33 };
The term in the standard to look for is odr-used if I recall correctly.
std::max takes its arguments by reference, not by value. Binding a reference to your static const requires an actual object, not just the value.