Home > database >  Undefined refenence error when compiling with C 11
Undefined refenence error when compiling with C 11

Time:03-14

The example program is here:

test.h

#pragma once
#include <bitset>

class Foo{
public:
    constexpr static std::bitset<9> hori1{0b111000000};
    bool Bar(const std::bitset<9> cells);
};

test.cpp

#include <bitset>
#include "test.h"

bool Foo::Bar(const std::bitset<9> cells){
    return hori1.any();
}

int main(){
    return 0;
}

When compiling this program without the --std=c 11 everything works fine.

$ g   -c test.cpp
$ g   test.o

But when the flag is included, I get this:

$ g   -c --std=c  11 test.cpp
$ g   test.o
/usr/bin/ld: test.o: warning: relocation against `_ZN3Foo5hori1E' in read-only section `.text'
/usr/bin/ld: test.o: in function `Foo::Bar(std::bitset<9ul>)':
test.cpp:(.text 0x17): undefined reference to `Foo::hori1'
/usr/bin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status

Why is this happening only in C 11? As far as I know, test.h is correctly included and therefore hori1 should be visible from within Foo. Any help is appreciated.

CodePudding user response:

hori1 is static. You have to define static data members in the implementation of the class.

test.cpp:

constexpr std::bitset<9> Foo::hori1;

bool Foo::Bar(const std::bitset<9> cells){
    return hori1.any();
}

int main(){
    return 0;
}

CodePudding user response:

The problem is that in C 11, we have to add a corresponding definition outside the class in exactly one translation unit for a static constexpr declaration of a class' data member. This is explained in more detail below:

C 11

class Foo
{
public:
    static constexpr int OUT_OF_BOUNDS_VALUE = -9999; //THIS IS A DECLARATION IN C  11 and C  14
    //other members here
};

In the above code snippet(which is for C 11,C 14), we have a declaration of the static data member OUT_OF_BOUNDS_VALUE inside the class. And so, in exactly one translation unit we have to provide a corresponding definition. Otherwise you'll get a linker error which can be seen here.

That is, in exactly one translation unit we should write:

constexpr int Foo::OUT_OF_BOUNDS;//note no initializer

C 17

class Foo
{
public:
    static constexpr int OUT_OF_BOUNDS_VALUE = -9999; //THIS IS A DEFINITION IN C  17
    //other members here
};

In the above code snippet(which is for C 17) we have a definition of the static data member OUT_OF_BOUNDS_VALUE inside the class. So since C 17, we don't have to provide the definition of OUT_OF_BOUNDS_VALUE anywhere else since we already have a definition for it inside the class and thus the same program works without any linker error.

  • Related