Mati
Mati

Reputation: 781

Why is the const static variable odr-used here?

Consider the following code:

class Test {
    public:
        static const int VALUE = 100;
};

std::tuple<int> foo(std::tuple<int> value) {
    return value;
}

int main()
{
    auto t = std::make_tuple(Test::VALUE); // This compiles fine
    auto t1 = foo(std::make_tuple(Test::VALUE)); // undefined reference to `Test::VALUE' linker error
}

According to the other question (What does it mean to "ODR-use" something?) and the answer:

In plain word, odr-used means something(variable or function) is used in a context where the definition of it must be present.

In the first case (variable t) the variable VALUE is not odr-used because only it' value is needed. But in the second case why the code won't compile? If I would pass t instead of passed rvalue(?) the code would compile fine. How the second case differs from the first and why VALUE is odr-used here?

Upvotes: 3

Views: 405

Answers (2)

Artyer
Artyer

Reputation: 40836

make_tuple takes the argument by const int& (since it's a constant lvalue and it takes a T&& argument), and binding a reference to a value is an ODR-use.

Both cases are ill-formed no diagnostic required. At high optimisation levels of gcc for example, the entire program is optimised out and there are no linker errors, where at no optimisation, both statements give linker errors.

To make it not an ODR use, you can convert it to an rvalue:

    // Various ways to force the lvalue-to-rvalue conversion
    auto t = std::make_tuple(int(Test::VALUE));
    auto t1 = foo(std::make_tuple((void(), Test::VALUE)));
    auto t2 = foo(std::make_tuple(+Test::VALUE));

(So std::make_tuple takes an int&& of a temporary)

Or you can make the definition inline (Easiest with constexpr):

class Test {
    public:
        static constexpr int VALUE = 100;
};

Upvotes: 3

KamilCuk
KamilCuk

Reputation: 141165

In the first case (variable t) the variable VALUE is not odr-used because only it' value is needed.

No. It's value is needed and it is ODR used.

But in the second case why the code won't compile?

Because the compiler you are using is not smart enough to optimize the second snippet of code. For example, both lines compile fine on gcc9.3 with -O1.

Upvotes: 2

Related Questions