If I pass an empty variable by value, even though it has no definition, is it safe and compliant?
I came across this issue while working on code, overloading |
, to make this print the contents of the vector v
:
v | print; // prints the vector v
The code I present here works for me with g++
and clang
, even though print
is an extern
variable with no linkage, but I wonder if I'm pushing the standard too far. This is for c++11/c++14, I guess this is solved in c++17 with inline
variables?
First, my initial code. The goal is to allow things like v|print
to print a vector. I have bigger goals too, related to ranges, but I'll focus on this tiny example here
struct print_tag_t {};
print_tag_t print;
void operator| (std::vector<int> & x, decltype(print) ) {
for(auto elem : x) {
std::cout << elem << '\n';
}
}
int main() {
std::vector<int> v{2,3,5,7};
v | print;
}
If I move this into a header, I can make the operator|
overload as inline
. But what about print
? I have found that I can make it extern
to avoid the linker error about duplicate symbols
// print.hh
struct print_tag_t {};
extern // extern, as I can't use inline on a variable
print_tag_t print;
inline
void operator| (std::vector<int> & x, decltype(print) ) {
for(auto elem : x) {
std::cout << elem << '\n';
}
}
This works for me. Somehow, even though print
has no definition, I can do v|print
. I guess it's because it's empty and therefore there is no value to inspect and therefore it never needs an address.
Are compilers required to allow my v|print
example to work? Where, to clarify, print
is extern
and hasn't been given any definition?
Defining Empty Variables with None and NaN Defining empty variables in Python is straightforward. If you wish to define a placeholder for a missing value that will not be used for calculations, you can define an empty variable using the None keyword.
A variable is considered empty if it does not exist or if its value equals false .
It means null is equal to undefined but not identical. When we define a variable to undefined then we are trying to convey that the variable does not exist . When we define a variable to null then we are trying to convey that the variable is empty.
Explicitly assigning a null value to variables that are no longer needed helps the garbage collector to identify the parts of memory that can be safely reclaimed.
Are compilers required to allow my
v|print
example to work? Where, to clarify, print isextern
and hasn't been given any definition?
No. You are odr-using print
(you're invoking an lvalue-to-rvalue conversion that doesn't yield a constant expression), which means you need a definition for print
. However, this is one of the categories of error that are ill-formed, no diagnostic required. And since the code in question doesn't take the address of print
anywhere, it's likely that the compiler will emit code that will not require such a definition, and hence the linker will be happy about it too. Typically, it will Just Work™.
A better solution would be to simply change the declaration to make print
constexpr
:
constexpr print_tag_t print{};
Now, v | print
wouldn't odr-use print
(since the lvalue-to-rvalue conversion would now be a constant expression), so no definition is even necessary, so the program is well-formed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With