Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange C++ link error

Tags:

c++

gcc

min

clang

When I try to compile this,

#include <iostream>

struct K{
    const static int a = 5;
};

int main(){
    K k;

    std::cout << std::min(k.a, 7);
}

I get following. Both gcc and clang gives similar error:

/tmp/x-54e820.o: In function `main':
x.cc:(.text+0xa): undefined reference to `K::a'
clang-3.7: error: linker command failed with exit code 1 (use -v to see invocation)

if I do following, it compiles without problem. Is this related to the way std::min is written?

#include <iostream>

struct K{
    const static int a = 5;
};

int main(){
    K k;

    std::cout << std::min((int) k.a, 7);  // <= here is the change!!!
}

another way to avoid the error is if I do my own min():

template <class T>
T min(T const a, T const b){
    return a < b ? a : b;
}

C-like preprocessor MIN also works OK.

like image 474
Nick Avatar asked Mar 22 '16 12:03

Nick


People also ask

How do you resolve a linking error?

You can fix the errors by including the source code file that contains the definitions as part of the compilation. Alternatively, you can pass . obj files or . lib files that contain the definitions to the linker.

What is linking error in C?

Linker Errors: These error occurs when after compilation we link the different object files with main's object using Ctrl+F9 key(RUN). These are errors generated when the executable of the program cannot be generated. This may be due to wrong function prototyping, incorrect header files.

What causes linker errors C++?

Linker errors occur when the linker is trying to put all the pieces of a program together to create an executable, and one or more pieces are missing. Typically, this can happen when an object file or libraries can't be found by the linker. Fixing linker errors can be tricky.

How do I fix the linker error C++ undefined symbol?

So when we try to assign it a value in the main function, the linker doesn't find the symbol and may result in an “unresolved external symbol” or “undefined reference”. The way to fix this error is to explicitly scope the variable using '::' outside the main before using it.


2 Answers

std::min accepts arguments by reference. Binding a reference to an object means that the object is odr-used (there is a code sample in [basic.def.odr]/2 pretty much the same as your sample).

However in the (int)k.a case, k.a is not odr-used; because it is performing lvalue-to-rvalue conversion which yields a constant expression. (There are a few other conditions here too but your code is OK).

If an object is odr-used then there must be exactly one definition of it; with no diagnostic required for violating this rule. So the first case may or may not be accepted; and the second case must be accepted.

In your own version of min, it takes arguments by value, which is similar to the (int)k.a case - the only action taken on k.a there is rvalue conversion to initialize the parameter of your min.

You can read the full set of rules about odr-use in section [basic.def.odr] of a C++ standard draft.

like image 124
M.M Avatar answered Oct 19 '22 22:10

M.M


This question is asked quite often. I believe it's a bug in clang. a is being detected as a constant expression too early and the compiler is not generating a definition of it. (see correction in comments)

std::min takes its arguments by const reference, so a definition must exist.

#include <iostream>

struct K{
    const static int a = 5;
};

int main(){
    K k;

    std::cout << std::min(k.a, 7);
}

Here's a portable workaround alternative:

#include <iostream>

struct K{
    constexpr static int a() { return 5; }
};


int main(){
    K k;

    std::cout << std::min(k.a(), 7);
}
like image 23
Richard Hodges Avatar answered Oct 19 '22 21:10

Richard Hodges