Undefined Reference to Static Constexpr Char[]

Undefined reference to static constexpr char[]

Add to your cpp file:

constexpr char foo::baz[];

Reason: You have to provide the definition of the static member as well as the declaration. The declaration and the initializer go inside the class definition, but the member definition has to be separate.

Undefined reference error to static constexpr data member

Somewhere in your code you are ODR-using numbers but you don't have a definition for it.

Here's a simple version of your problem (wandbox):

#include <iostream>
#include <cstdint>

class shift7seg {
public:
static constexpr std::uint8_t numbers[10] = {};
};

int main() {
// taking the address is ODR-use
std::cout << &shift7seg::numbers[0] << '\n';
}

Possible solutions are

  1. compile with -std=c++17 (or later) where all static constexpr data members are implicitly inline and don't need out-of-line definitions

  2. Add an out-of-line definition in your implementation file (shift7seg.cpp) like this (wandbox):

constexpr std::uint8_t shift7seg::numbers[10];

Undefined reference error for static constexpr member

This behaviour is vexing me time and again. The cause of the trouble is that your

A(int n): v(n, A::kDefaultValue) {}

odr-uses the static constexpr member, since the constructor of v takes a constant reference second argument. Odr-usage requires a definition somewhere, i.e.

const int A::kDefaultValue;

in some compilation unit (which is compiled and linked to main()). This requirement has been dropped in C++17 and the corresponding definition (as above) deprecated.

However, a definition is not always possible (for example for members of class templates) and the simplest way to avoid both the definition and your error is

A(int n): v(n, int(A::kDefaultValue)) {}

which creates a temporary to be passed to the constructor of v (but since the latter is fully inline, the compiler may optimise that away).

static constexpr undefined reference error on clang

C++17 introduces the rule that static constexpr member variables are implicitly inline (P0386). Inline variables didn't exist before C++17.

This means that in earlier C++ standards, a compiler may need a static constexpr member variable to be defined. If its address is taken, for example.

In C++ standards earlier than C++17, you can ensure that your code is well-formed, by separately defining the static variable.

struct repo {
static constexpr const char *x = "sth";
};

constexpr const char *repo::x;

Edit:

It should be noted that with optimizations off, none of the examples successfully link.

It is an artifact of the optimizer that sometimes, a reference to a value can be flattened to the value itself, in which case the linker won't look for the missing symbol.

Undefined reference to static constexpr

The out-of-line definiton is the same as for other static (non integral) members, minus the initialization:

template<size_t N>
constexpr std::array<char, N> Foo<N>::arr;

Like other static members, this goes in a header - like the class template itself.

Undefined reference to static constexpr char[][]

The definition needs to go outside the class, while the initializer belongs inside the class.

constexpr char A::dict[][3];

Cannot declare static constexpr char []

1) Is there a way to declare a static constexpr char [] inside struct/class?

Yes; it's simple.

The following is a full working example

struct bar
{ static constexpr char value[] = "foo"; };

constexpr char bar::value[];

int main ()
{
std::cout << bar::value << std::endl; // print foo
}

I suppose You forgot the bar::value[] row.

2) If 1) is false is there a cleanest solution to overcome this static constexpr char * ????

Not applicable.

3) Or the old static const char [] is still the best approach for this case?

Depend from the problem you have to solve; but usually I suggest to avoid C-style arrays and use the new C++11 std::array

4) I've tested a solution that works but far from being "clean" [...] It works fine but I have to declare the size of the char std::array :(

I propose you a solution (unfortunately work starting from C++14, but isn't too difficult make a C++11 version) to detect the correct size from "Hell" passed as parameter.

Observe the use of std::make_index_sequence and std::index_sequence to pass the single chars from the char[] variable to the std::array.

template <std::size_t Dim, std::size_t ... Is>
constexpr std::array<char, Dim> gceH (char const (&str)[Dim],
std::index_sequence<Is...> const &)
{ return { { str[Is]... } }; }

template <std::size_t Dim>
constexpr std::array<char, Dim> getConstExpr (char const (&str)[Dim])
{ return gceH(str, std::make_index_sequence<Dim>{}); }

int main ()
{
constexpr auto f = getConstExpr("Hell");

static_assert( 5U == f.size(), "!" );
}

-- EDIT --

As suggested by Swift (thanks!) using a template type, instead char, transform getConstExpr() in a more flexible function.

So getConstExpr() and the helper function (gceH()) can be written as follows

template <typename T, std::size_t Dim, std::size_t ... Is>
constexpr std::array<T, Dim> gceH (T const (&str)[Dim],
std::index_sequence<Is...> const &)
{ return { { str[Is]... } }; }

template <typename T, std::size_t Dim>
constexpr std::array<T, Dim> getConstExpr (T const (&str)[Dim])
{ return gceH(str, std::make_index_sequence<Dim>{}); }

Undefined reference to static constexpr string (except if it's a pointer)

An object or function must be defined if it is odr-used. In some cases objects and functions are not odr-used and in those cases you don't have to define them. Whether or not the declaration of a static class member has an initializer, it is still not a definition. In all cases the rule is that an out-of-class definition at an enclosing namespace scope is required if the static member is odr-used.

The intuition is that "odr-used" means "the linker needs its address". If a constexpr variable is only used in ways that require its value---and never its address---then it may avoid being odr-used. In such cases the compiler simply inlines its value, and it does not need to be defined, because the linker doesn't need its address. That's the case with const char* Something<int>::str, but not const char Something<int>::str[].

"But they're the same!", you shout. Not so. For when str is a const char*, its value is the address of the string literal "int". The address of the string literal is needed, but not the address of str itself. The former is the value of str and it satisfies the requirements for not being odr-used; the compiler can just inline it. But when str is a const char[], its value is the string literal "int" itself. When you try to output it using istream::operator<<, it is implicitly converted into a const char*. But the const char*'s value is the address of the string literal, that is, the address of Something<int>::str. Therefore in this case Something<int>::str is odr-used; its address is needed.

There is logic in the standard that can be used to determine precisely when a variable is odr-used ([basic.def.odr]). But I'm not going to quote it because it's the most confusing section of the entire standard. I will say that in the case where you have const char* Something<int>::str, the lvalue-to-rvalue conversion is immediately applied, which is one of the conditions for it to not be odr-used; and in the case where you have const char Something<int>::str[], the array-to-pointer conversion is immediately applied, and that doesn't satisfy the condition.



Related Topics



Leave a reply



Submit