void.pointer
void.pointer

Reputation: 26365

Linker error with static constant that doesn't seem to be odr-used

The definition in the standard for odr-used is pretty confusing when you get into the details (at least, for me it is). I generally rely on the informal definition of "If a reference is taken", except when an lvalue-to-rvalue conversion is available. For integral constants, they should be treated as rvalues, which seems like it should be excluded from the reference rule. Here is my sample code that is failing to link:

class Test
{
public:
    Test();
    static constexpr int MIN_VALUE { 5 };
    int m_otherValue = 10;
};

Test::Test()
{
    m_otherValue = std::max(m_otherValue, MIN_VALUE);
}

int main()
{
    Test t;
}

And the linker error that I get:

clang++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
/tmp/main-e2122e.o: In function `Test::Test()':
main.cpp:(.text+0x2): undefined reference to `Test::MIN_VALUE'
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Live sample: http://coliru.stacked-crooked.com/a/4d4c27d6b7683fe8

Why is the definition of MIN_VALUE required? It's just a constant to a literal value, the compiler should optimize this out as std::max(m_otherValue, 5). So I just don't get it.

Upvotes: 4

Views: 181

Answers (2)

Some programmer dude
Some programmer dude

Reputation: 409196

If you read a reference for std::max you will see that it takes it arguments by reference, and according to this odr-used reference

Informally, an object is odr-used if ... a reference is bound to it ...

Since you pass MIN_VALUE to a function which takes a reference, the member is odr-used and needs a separate definition.

Upvotes: 1

user743382
user743382

Reputation:

std::max takes its arguments by reference, not by value. Performing the lvalue-to-rvalue conversion and then constructing a temporary object from that rvalue is not allowed. std::max could be checking that the two arguments are references to the same object, for all the compiler knows, and that check would be required to evaluate as true if called as std::max(MIN_VALUE, MIN_VALUE).

Upvotes: 7

Related Questions