Are variables mapped in a function expression that take arguments by reference but return by odr?

Given the code snippet:

struct S {
    static const int var = 0; 
}; 

int function(const int& rVar){
    return rVar; 
}

int main()
{
    return function(S::var); 
}

      

Compiled with gcc 5.4.0

:

g++ -std=c++17 main.cpp -o test

      

results in the following binding error:

/tmp/ccSeEuha.o: In function `main': main.cpp:(.text+0x15): undefined reference to `S::var' collect2: error: ld returned 1 exit status

ยง3.3

from the ISO C ++ 17 standard standard n4296

:

The variable x whose name appears as a potentially evaluable expression ex is odr-used by ex, unless an lvalue-to-rvalue conversion (4.1) to x is applied yields a constant expression (5.20) that does not call any non-trivial functions and if x is an object, ex is a member of the set of potential results of e, where either an lvalue-to-rvalue conversion (4.1) is applied to e [adding bold formatting] or e is an expression with a value discarded (section 5).

Q: Why is a variable definition required here var

? Doesn't var

denote an integer object that appears in the potentially-evaluted expression of S::var

an outter function call expression that does take a parameter by reference, but which finally gets an lvalue-to-rvalue conversion applied, and thus isn't used as stated in the paragraph ?

+3


source to share


2 answers


but to which finally the lvalue-to-rvalue conversion is applied and thus not using odr as stated in the paragraph?

The lvalue-to-rval conversion in another expression is irrelevant. The lvalue-to-rvalue conversion does not apply to the subexpression S::var

in the expression function(S::var)

, so no exception is applied.




Given common sense, instead of parsing the rule: function

can be defined in a different translation unit, so the compiler cannot know how this link will be used. It cannot simply send a copy of the function's value and hopes that the function definition will not use the object in a way that requires the definition of the referenced object. Likewise, when compiling a function, the compiler cannot assume that all function calls would send anything other than a reference to an existing object.

Technically, I suppose there might be an even more complex exception for built-in function reference arguments, but there is no such exception in the standard. And it shouldn't be, since in these cases this mandatory extension would be required. In practice, the compiler can behave exactly as required if the inline function is expanded, since odr violations have undefined behavior.

+5


source


The example is shown explicitly above the paragraph you provided : in function(S::var);

, S::var

odr is used.

The reason is that, because it function

accepts its parameter by ref (and not by value), no lvalue to rvalue conversion occurs.

But if you change function

to accept its argument by value:



int function(const int rVar){
    return rVar; 
}

      

then the lvalue to rvalue is converted and S::var

odr is no longer used. And the program no longer shows undefined link ...

+1


source







All Articles