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?
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;
};
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.
Related
#include <variant>
struct S {
constexpr auto f() -> void {
// deleting the next line creates an error
if(std::holds_alternative<int>(m_var))
m_var.emplace<double>(5.0);
}
std::variant<int, double> m_var;
};
int main() {
return 0;
}
std::variant has a non-constexpr member function emplace(). In general you can't use that in constexpr functions. You can however if you surround that call by a condition that uses std::holds_alternative() on that type. Also other constexpr functions as long as they're member functions in that class.
I'm having trouble to understand what' going on. My first reaction was to say that's a bug. That condition can't possibly be more constexpr than no condition at all. But maybe that was premature. Can anyone shed some light on this? Why is it that emplace() is not constexpr but (equal-type) assignments are?
Edit: Maybe to expand a bit: One guess is that constructors and destructors of the involved variants could be non-constexpr and that's why emplace etc are not. But the fun thing is that you can use conditions like this to compile the function as constexpr even when you explicitly abuse a non-constexpr constructor. That voids that argument.
godbolt: here.
You don't actually need to delve much into std::variant to reason about this. This is mostly about how constant expressions work. constexpr functions must be defined in a way that allows for evaluation in a constant expression. It doesn't matter if for some arguments we run into something that can't appear in a constant expression, so long as for other arguments we obtain a valid constant expression. This is mentioned explicitly in the standard, with an exeample
[dcl.constexpr]
5 For a constexpr function or constexpr constructor that is
neither defaulted nor a template, if no argument values exist such
that an invocation of the function or constructor could be an
evaluated subexpression of a core constant expression, or, for a
constructor, a constant initializer for some object
([basic.start.static]), the program is ill-formed, no diagnostic
required. [ Example:
constexpr int f(bool b)
{ return b ? throw 0 : 0; } // OK
constexpr int f() { return f(true); } // ill-formed, no diagnostic required
struct B {
constexpr B(int x) : i(0) { } // x is unused
int i;
};
int global;
struct D : B {
constexpr D() : B(global) { } // ill-formed, no diagnostic required
// lvalue-to-rvalue conversion on non-constant global
};
— end example ]
See how f(bool) is a valid constexpr function? Even though a throw expression may not be evaluated in a constant expression, it can still appear in a constexpr function. It's no problem so long as constant evaluation doesn't reach it.
If there is no set of arguments for which a constexpr function can be used in a constant expression, the program is ill-formed. No diagnostic is required for this sort of ill-formed program because checking this condition from the function definition alone is intractable in general. Nevertheless, it's invalid C++, even if the compiler raises no error. But for some cases, it can be checked, and so a compiler could be obliged raise a diagnostic.
Your f without a condition falls into this category of ill-formed constructs. No matter how f is called, its execution will result in invoking emplace, which cannot appear in a constant expression. But it's easy enough to detect, so your compiler tells you it's a problem.
Your second version, with the condition, no longer invokes emplace unconditionally. Now its conditional. The condition itself is relying on a constexpr function, so it's not immediately ill-formed. Everything would depend on the arguments to the function (this included). So it doesn't raise an error immediately.
struct A{
constexpr operator bool()const{ return true; }
};
int main(){
auto f = [](auto v){ if constexpr(v){} };
A a;
f(a);
}
clang 6 accepts the Code, GCC 8 rejects it with:
$ g++ -std=c++17 main.cpp
main.cpp: In lambda function:
main.cpp:6:37: error: 'v' is not a constant expression
auto f = [](auto v){ if constexpr(v){} };
^
Who is correct and why?
When I take the parameter per reference, both reject the code:
struct A{
constexpr operator bool()const{ return true; }
};
int main(){
auto f = [](auto& v){ if constexpr(v){} };
constexpr A a;
f(a);
}
Compiled with clang 6:
$ clang++ -std=c++17 main.cpp
main.cpp:6:40: error: constexpr if condition is not a constant expression
auto f = [](auto& v){ if constexpr(v){} };
^
main.cpp:8:6: note: in instantiation of function template specialization
'main()::(anonymous class)::operator()<const A>' requested here
f(a);
^
1 error generated.
When I copy the parameter into a local variable both accept the code:
struct A{
constexpr operator bool()const{ return true; }
};
int main(){
auto f = [](auto v){ auto x = v; if constexpr(x){} };
A a;
f(a);
}
Edit: I am sure that the second and third cases will be handled correctly by both compilers. I don't know what the rule is, though.
In the first case I suspect that clang is right, because the case resembles the second. I would like to know if in the first case clang or GCC is correct and which rules in the second case makes the use of the not-constexpr variable v invalid and in the third case x valid.
Edit 2: First Question is clear now:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84421
clang was right, GCC 7 accepted the code as well. The bug will be fixed in the final version of GCC 8.
Clang is correct in all cases. [Full disclosure: I'm a Clang developer]
The question in all cases reduces to this: can we call a constexpr member function on v within a constant expression?
To answer this question, we need to look at [expr.const]p2, which says:
An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (6.8.1), would evaluate one of the following expressions:
...
an id-expression that refers to a variable or data member of reference type unless the reference has a
preceding initialization and either
it is initialized with a constant expression or
its lifetime began within the evaluation of e;
...
None of the other rules prohibit any of your examples. In particular, you are allowed to name local variables in a constant expression if they are not of reference type. (You are not allowed to perform lvalue-to-rvalue conversions on them -- that is, read their values -- unless their value is known (for instance, because they're constexpr), and you're not allowed to end up referring to the address of such a variable, but you are allowed to name them.)
The reason that the rules are different for entities of reference type is that merely naming an entity of reference type causes the reference to be immediately resolved, even if you don't do anything with the result, and resolving a reference requires knowing what it's bound to.
So: the first example is valid. The *this value of the constexpr member function is bound to the local variable a. It doesn't matter that we don't know what object that is, because the evaluation doesn't care.
The second example (where v is of reference type) is ill-formed. Merely naming v requires resolving it to the object it's bound to, which can't be done as part of the constant expression evaluation because we have no idea what it'll end up being bound to. It doesn't matter that the later evaluation steps won't use the resulting object; references are resolved immediately when they're named.
The third example is valid for the same reason as the first. Notably, the third example remains valid even if you change v to be of reference type:
auto f = [](auto &v) { auto x = v; if constexpr (x) {} };
A a;
f(a);
... because x is, once again, a local variable that we can name within a constant expression.
Please consider the following two C++14 programs:
Program 1:
struct S { constexpr int f() const { return 42; } };
S s;
int main() { constexpr int x = s.f(); return x; }
Program 2:
struct S { constexpr int f() const { return 42; } };
int g(S s) { constexpr int x = s.f(); return x; }
int main() { S s; return g(s); }
Are neither, either or both of these programs ill-formed?
Why/why not?
Both programs are well-formed. The C++14 standard requires that s.f() be a constant expression because it is being used to initialize a constexpr variable, and in fact it is a core constant expression because there's no reason for it not to be. The reasons that an expression might not be a core constant expression are listed in section 5.19 p2. In particular, it states that the evaluation of the expression would have to do one of several things, none of which are done in your examples.
This may be surprising since, in some contexts, passing a non-constant expression to a constexpr function can cause the result to be a non-constant expression even if the argument isn't used. For example:
constexpr int f(int) { return 42; }
int main()
{
int x = 5;
constexpr auto y = f(x); // ill-formed
}
However, the reason this is ill-formed is because of the lvalue-to-rvalue conversion of a non-constant expression, which is one of the things that the evaluation of the expression is not allowed to do. An lvalue-to-rvalue conversion doesn't occur in the case of calling s.f().
I can't seem to find a compelling passage or example in the standard that directly addresses the issue of calling a constexpr member function on a non-constexpr instance, but here are some that may be of help (from draft N4140):
[C++14: 7.1.5/5]:
For a non-template, non-defaulted constexpr function or a non-template, non-defaulted, non-inheriting
constexpr constructor, if no argument values exist such that an invocation of the function or constructor
could be an evaluated subexpression of a core constant expression (5.19), the program is ill-formed; no
diagnostic required.
constexpr int f(bool b)
{ return b ? throw 0 : 0; } // OK
constexpr int f() { return f(true); } // ill-formed, no diagnostic required
From this I take that the program is not outright ill-formed just because a constexpr function has a possible non-constexpr path.
[C++14: 5.19]:
int x; // not constant
struct A {
constexpr A(bool b) : m(b?42:x) { }
int m;
};
constexpr int v = A(true).m; // OK: constructor call initializes
// m with the value 42
constexpr int w = A(false).m; // error: initializer for m is
// x, which is non-constant
This is somewhat closer to your example programs, here a constexpr constructor may reference a non-constexpr variable depending on the value of the argument, but there is no error if this path is not actually taken.
So I don't think either program you presented should be ill-formed, but I cannot offer convincing proof :)
This sounds like a quiz question, and not presented by a student, but the professor testing the public on stackoverflow, but let's see...
Let's start with the One Definition Rule. It's clear neither version violates that, so they both pass that part.
Then, to syntax. Neither have syntax failures, they'll both compile without issue if you don't mind the potential blend of a syntax and semantic issue.
First, the simpler semantic issue. This isn't a syntax problem, but f(), in both versions, is the member of a struct, and the function clearly makes no change to the owning struct, it's returning a constant. Although the function is declared constexpr, it is not declared as const, which means if there were some reason to call this as a runtime function, it would generate an error if that attempt were made on a const S. That affects both versions.
Now, the potentially ambiguous return g(S()); Clearly the outer g is a function call, but S may not be so clear as it would be if written return g(S{}); With {} initializing S, there would be no ambiguity in the future should struct S be expanded with an operator() (the struct nearly resembles a functor already). The constructor invoked is automatically generated now, and there is no operator() to create confusion for the compiler at this version, but modern C++14 is supposed to offer clearer alternatives to avoid the "Most Vexing Parse", which g(S()) resembles.
So, I'd have to say that based on semantic rules, they both fail (not so badly though).
I am a bit confused by the static in-class initialization of a const member. For example, in the code below:
#include <iostream>
struct Foo
{
const static int n = 42;
};
// const int Foo::n; // No ODR
void f(const int& param)
{
std::cout << param << std::endl;
}
int g(const int& param)
{
return param;
}
template<int N>
void h()
{
std::cout << N << std::endl;
}
int main()
{
// f(Foo::n); // linker error, both g++/clang++
std::cout << g(Foo::n) << std::endl; // OK in g++ only with -O(1,2 or 3) flag, why?!
h<Foo::n>(); // this should be fine
}
Live example
I do not define Foo::n (the line is commented). So, I expect the call f(Foo::n) to fail at link time, and indeed it does. However, the following line std::cout << g(Foo::n) << std::endl; compiles and links fine only by gcc (clang still emits a linker error) whenever I use an optimization flag such as -O1/2/3.
Why does gcc (tried with gcc5.2.0 and gcc 4.9.3) compile and link the code when the optimization is turned on?
And am I correct to say that the only usage of in-class static const members is in constant expressions, such as template parameters like in the h<Foo::n> call, in which case the code should link?
I suppose that the compiler performs the following actions during the optimization:
The value const static int n is inlined everywhere. No memory is allocated for the variable n, references to it becomes invalid. The function f() need a reference to n so the program is not compiled.
The function g is short and simple. It is effectively inlined and optimized. After the optimization, the function g does not need a reference to n, it just returns constant value 42.
The solution is to define the variable outside the class:
struct Foo
{
const static int n;
};
const int Foo::n = 42;
ODR violations do not require a diagnostic, from the draft C++ standard standard section 3.2 [basic.def.odr] (emphasis mine going forward):
Every program shall contain exactly one definition of every non-inline
function or variable that is odr-used in that program; no diagnostic
required.
So inconsistent behavior at different optimization levels is perfectly conformant behavior.
Informally a variable is odr-used if:
its address is taken, or a reference is bound to it, and a function is odr-used if a function call to it is made or its address is taken. If an object or a function is odr-used, its definition must exist somewhere in the program; a violation of that is a link-time error.
So both f and g will be odr-uses and require a definition.
The relevant C++14 quote on odr-use would be from section [basic.def.odr]:
A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying
the lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.19) that does not invoke any nontrivial
functions and, if x is an object, ex is an element of the set of potential results of an expression e,
where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression [...]
The wording in C++11 is similar, the changes from C++11 to C++14 are reflected in defect report 712.
Before C++11 it is a bit more complicated but in principle the same for this case.
Formally, ODR violations are undefined behaviour, so the compiler may exhibit any behaviour it likes. That's why the behaviour changes with optimization level and compiler- the compiler has no obligation to maintain a particular behaviour.
There is no definition at all. GCC 4.9.2 doesn't compile and link that with any flags.
Note, that:
const static int n = 42;
is a declaration and initializer, but not a definition.
I ran into an interesting issue today. Consider this simple example:
template <typename T>
void foo(const T & a) { /* code */ }
// This would also fail
// void foo(const int & a) { /* code */ }
class Bar
{
public:
static const int kConst = 1;
void func()
{
foo(kConst); // This is the important line
}
};
int main()
{
Bar b;
b.func();
}
When compiling I get an error:
Undefined reference to 'Bar::kConst'
Now, I'm pretty sure that this is because the static const int is not defined anywhere, which is intentional because according to my understanding the compiler should be able to make the replacement at compile-time and not need a definition. However, since the function takes a const int & parameter, it seems to be not making the substitution, and instead preferring a reference. I can resolve this issue by making the following change:
foo(static_cast<int>(kConst));
I believe this is now forcing the compiler to make a temporary int, and then pass a reference to that, which it can successfully do at compile time.
I was wondering if this was intentional, or am I expecting too much from gcc to be able to handle this case? Or is this something I shouldn't be doing for some reason?
It's intentional, 9.4.2/4 says:
If a static data member is of const integral or const enumeration type,
its declaration in the class
definition can specify a
constant-initializer which shall be an
integral constant expression (5.19) In
that case, the member can appear in
integral constant expressions. The
member shall still be defined in a
namespace scope if it is used in the
program
When you pass the static data member by const reference, you "use" it, 3.2/2:
An expression is potentially evaluated
unless it appears where an integral
constant expression is required (see
5.19), is the operand of the sizeof operator (5.3.3), or is the operand of
the typeid operator and the expression
does not designate an lvalue of
polymorphic class type (5.2.8). An
object or non-overloaded function is
used if its name appears in a
potentially-evaluated expression.
So in fact, you "use" it when you pass it by value too, or in a static_cast. It's just that GCC has let you off the hook in one case but not the other.
[Edit: gcc is applying the rules from C++0x drafts: "A variable or non-overloaded function whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied.". The static cast performs lvalue-rvalue conversion immediately, so in C++0x it's not "used".]
The practical problem with the const reference is that foo is within its rights to take the address of its argument, and compare it for example with the address of the argument from another call, stored in a global. Since a static data member is a unique object, this means if you call foo(kConst) from two different TUs, then the address of the object passed must be the same in each case. AFAIK GCC can't arrange that unless the object is defined in one (and only one) TU.
OK, so in this case foo is a template, hence the definition is visible in all TUs, so perhaps the compiler could in theory rule out the risk that it does anything with the address. But in general you certainly shouldn't be taking addresses of or references to non-existent objects ;-)
If you're writing static const variable with initializer inside class declaration it's just like as if you've written
class Bar
{
enum { kConst = 1 };
}
and GCC will treat it the same way, meaning that it does not have an address.
The correct code should be
class Bar
{
static const int kConst;
}
const int Bar::kConst = 1;
This is a really valid case. Especially because foo could be a function from the STL like std::count which takes a const T& as its third argument.
I spent much time trying to understand why the linker had problems with such a basic code.
The error message
Undefined reference to 'Bar::kConst'
tells us that the linker cannot find a symbol.
$nm -C main.o
0000000000000000 T main
0000000000000000 W void foo<int>(int const&)
0000000000000000 W Bar::func()
0000000000000000 U Bar::kConst
We can see from the 'U' that Bar::kConst is undefined. Hence, when the linker tries to do its job, it has to find the symbol. But you only declare kConst and don't define it.
The solution in C++ is also to define it as follows:
template <typename T>
void foo(const T & a) { /* code */ }
class Bar
{
public:
static const int kConst = 1;
void func()
{
foo(kConst); // This is the important line
}
};
const int Bar::kConst; // Definition <--FIX
int main()
{
Bar b;
b.func();
}
Then, you can see that the compiler will put the definition in the generated object file:
$nm -C main.o
0000000000000000 T main
0000000000000000 W void foo<int>(int const&)
0000000000000000 W Bar::func()
0000000000000000 R Bar::kConst
Now, you can see the 'R' saying that it is defined in the data section.
The proper way in C++17 would be to simply make the variable constexpr:
static constexpr int kConst = 1;
constexpr static data member are implicitly inline.
You can also replace it by a constexpr member function:
class Bar
{
static constexpr int kConst() { return 1; };
};
g++ version 4.3.4 accepts this code (see this link). But g++ version 4.4.0 rejects it.
I think this artefact of C++ means that any time that Bar::kConst is referred to, its literal value is used instead.
This means that in practise there is no variable to make a reference point to.
You may have to do this:
void func()
{
int k = kConst;
foo(k);
}
Simple trick: use + before the kConst passed down the function. This will prevent the constant from being taken a reference from, and this way the code will not generate a linker request to the constant object, but it will go on with the compiler-time constant value instead.
I experienced the same problem as mentioned by Cloderic (static const in a ternary operator: r = s ? kConst1 : kConst2), but it only complained after turning off compiler optimization (-O0 instead of -Os). Happened on gcc-none-eabi 4.8.5.