Static constexpr members seem not to go along with std::min [duplicate] - c++

This question already has an answer here:
Why does constexpr static member (of type class) require a definition?
(1 answer)
Closed 7 years ago.
Here is a problem the reason of which is quite obscure to me, but the workaround of which is fortunately quite easy.
Consider the following code (let me call it my main.cpp):
#include <algorithm>
struct Foo {
static constexpr float BAR = .42;
float operator()() const noexcept {
float zero = .0;
return std::min(zero, BAR);
}
};
int main() {
Foo foo;
foo();
}
When I tried to compile it, I got the error:
foobar:~/stackoverflow$ g++ -std=c++11 main.cpp
/tmp/ccjULTPy.o: In function 'Foo::operator()() const':
main.cpp:(.text._ZNK3FooclEv[_ZNK3FooclEv]+0x1a): undefined reference to `Foo::BAR'
collect2: error: ld returned 1 exit status
The same happens (quite obviously) also if I use the following statement:
return std::min(zero, Foo::BAR);
Below a slightly modified version of the example above.
This one compiles with no error, even though I'm still referring to the BAR member:
#include <algorithm>
struct Foo {
static constexpr float BAR = .42;
float operator()() const noexcept {
float zero = .0;
float bar = BAR;
return std::min(zero, bar);
}
};
int main() {
Foo foo;
foo();
}
I didn't succeed in understanding why the latter version compiles fine while the former ends with an error.
As far as I know, both the versions are correct and should compile, but I strongly suspect that I'm missing something important here.
Any suggestion?
Here my compiler's version: g++ (Debian 5.3.1-5) 5.3.1 20160101.

The selected prototype for min is
template<class T>
/* constexpr since C++14 */ const T& min( const T& a, const T& b );
The pertinent point is that it takes the argument by reference, meaning it One-Definition-Rule (ODR)-uses it.
And you never defined it, you only declared it in your class (with an initializer):
static constexpr float BAR = .42;
Which is good enough for copying and otherwise using the value, but not for using it as anything but a prvalue.
See Why does constexpr static member (of type class) require a definition?
Violation of the ODR (whose finer points are fine and voluminuous indeed) need not be diagnosed:
3.2 One definition rule [basic.def.odr]
4 Every program shall contain exactly one definition of every non-inline function or variable that is odr-used
in that program; no diagnostic required. The definition can appear explicitly in the program, it can be found
in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see 12.1, 12.4 and
12.8). An inline function shall be defined in every translation unit in which it is odr-used.

Related

Why does static_assert constexpr function not work in non-template struct but works free or in template? [duplicate]

I have the following code:
class MyClass
{
static constexpr bool foo() { return true; }
void bar() noexcept(foo()) { }
};
I would expect that since foo() is a static constexpr function, and since it's defined before bar is declared, this would be perfectly acceptable.
However, g++ gives me the following error:
error: ‘static constexpr bool MyClass::foo()’ called in a constant expression
This is...less than helpful, since the ability to call a function in a constant expression is the entire point of constexpr.
clang++ is a little more helpful. In addition to an error message stating that the argument to noexcept must be a constant expression, it says:
note: undefined function 'foo' cannot be used in a constant expression
note: declared here
static constexpr bool foo() { return true; }
^
So...is this a two-pass-compilation problem? Is the issue that the compiler is attempting to declare all the member functions in the class before any of them are defined? (Note that outside of the context of a class, neither compiler throws an error.) This surprises me; intuitively, I don't see any reason for static constexpr member functions not to be useable in any and all constant expressions, inside the class or out.
As T.C. demonstrated with some links in a comment, the standard is not quite clear on this; a similar problem arises with trailing return types using decltype(memberfunction()).
The central problem is that class members are generally not considered to be declared until after the class in which they're declared is complete. Thus, regardless of the fact that foo is static constexpr and its declaration precedes that of bar, it cannot be considered "available" for use in a constant expression until MyClass is complete.
As pointed out by Shafik Yaghmour, there is some attempt within the standard to avoid a dependency on the ordering of members within a class, and obviously allowing the example in the original question to compile would introduce an ordering dependency (since foo would need to be declared before bar). However, there is already a minor dependency on ordering, because although constexpr functions can't be called inside noexcept, a noexcept expression itself might depend on an earlier declaration inside the class:
class MyClass
{
// void bar() noexcept(noexcept(foo())); // ERROR if declared here
static constexpr bool foo();
void bar() noexcept(noexcept(foo())); // NO ERROR
}
(Note that this is not actually a violation of 3.3.7, since there is still only one correct program that is possible here.)
This behavior may actually be a violation of the standard; T.C. points out (in a comment below) that foo here should actually be looked up in the scope of the whole class. Both g++ 4.9.2 and clang++ 3.5.1 fail with an error when bar is declared first but compile with no errors or warnings when foo is declared first. EDIT: clang++ trunk-revision 238946 (from shortly before the release of 3.7.0) does not fail when bar is declared first; g++ 5.1 still fails.
Intriguingly, the following variation causes a "different exception specifier" with clang++ but not with g++:
class MyClass
{
static constexpr bool foo2();
void bar2() noexcept(noexcept(foo2()));
};
constexpr bool MyClass::foo2() { return true; }
void MyClass::bar2() noexcept(noexcept(MyClass::foo2())) { }
According to the error, the noexcept specification for the declaration of bar2 evaluates to noexcept(false), which is then considered a mismatch for noexcept(noexcept(MyClasss::foo2())).

C++: (NOT duplicate) integral static member initialized (not just declared!) inside a class causes linker error, why?

EDIT: I'm not asking how to make the code work, but why it has error. Also, the static member is not only declared inside the class, but also has been initialized with a value (at least it appears to have), hence I don't think it's redundant. Also, this question asks beyond that, so please don't close it. It is not a duplicate.
Say class A has a static member data defined inside. The shell record below does not link (ld: undefined reference).
Note that since C++11, std::vector<>::push_back() accepts either a const lvalue reference (const value_type&) or an rvalue reference (value_type&& val). Moreover, even if it doesn't accept an rvalue reference, an rvalue can be bound to a const lvalue reference.
$ cat class.h
struct A {
static const int STAT_MEMBER = 1;
A();
int a;
};
$ cat class.cc
#include "class.h"
#include <vector>
using namespace std;
A::A() { a = STAT_MEMBER; }
int main() {
vector<int> v;
v.push_back(A::STAT_MEMBER);
}
$ g++ -std=c++14 class.cc -o class
/tmp/ccNXDnyu.o: In function `main':
class.cc:(.text+0x2f): undefined reference to `A::STAT_MEMBER'
collect2: error: ld returned 1 exit status
$
Question:
(1) is A::STATIC_MEMBER an rvalue? (but regardless of it being an rvalue or an lvalue, it shouldn't cause an error in linker -- it should have been fine or have caused an error in compiler)
(2) why didn't the compiler/linker complain about STATIC_MEMBER in A::A()?
(3) why didn't the compiler complain about STATIC_MEMBER in main()?
(4) why did the linker complain about STATIC_MEMBER in main()?
I know this problem should be gone if the static member is declared inside the class but defined outside the class, but I'm mostly interested the problem above.
G++ version: g++-6 (Ubuntu/Linaro 6.3.0-18ubuntu2~14.04) 6.3.0 20170519
The reason is quite easy:
If you use a value, the compiler can use the known value to your undefined but declared static const member.
But the vector::push_back takes the reference to the value! The reference is the address and there is no address of an undefined object, only the value of the object is known.
You can reduce the code to this, which simplifies it a bit:
struct A {
static const int STAT_MEMBER = 1;
};
void Works( const int i ){} // this takes the VALUE of the variable
void Fail( const int& i){} // this takes the ADDRESS of the variable
// but there is no object which can be
// addressed, because it is not defined!
int main()
{
Works( A::STAT_MEMBER );
Fail( A::STAT_MEMBER );
}
Simply comment in and out to get linker error or not!
This only works in C++17, so just wait a little bit (or turn on the C++17 support flag in your compiler).
From the cppreference.com:
A static data member may be declared inline. An inline static data member can be defined in the class definition and may specify an initializer. It does not need an out-of-class definition:
struct X
{
inline static int n = 1;
};
This can be simplified to this:
struct A { static const int s = 1; };
int main()
{
int a1 = A::s; // OK
int const & a2 = A::s; // error,
int const * a3 = &A::s; // same thing
}
a1 case works because of the special treatment that integral constants receive. Basically compiler knows the value of s at compile time and does not need to access storage. This also allows s to be used as template parameters:
::std::array<int,A::s> xx;

Undefined reference error when initializing unique_ptr with a static const

When I try to use a static const to initialize a unique_ptr, I get an "undefined reference" error. However, when I new a pointer using the same constant, the symbol seems to be magically defined.
Here is a simple program that reproduces the error:
Outside_library.h
class Outside_library
{
public:
static const int my_const = 100;
};
main.cpp
#include "Outside_library.h"
#include <iostream>
#include <memory>
class My_class
{
public:
My_class(int num)
{
m_num = num;
};
virtual ~My_class(){};
private:
int m_num;
};
int main(int, char* [])
{
My_class* p_class = new My_class(Outside_library::my_const);
delete p_class;
// ==== ERROR HERE: When I comment this line out, the program runs fine.
std::unique_ptr<My_class> p_unique
= std::make_unique<My_class>(Outside_library::my_const);
std::cout << "I made it through!" << std::endl;
return 0;
}
I compiled the program using
g++ main.cpp -std=c++14
and got the following error.
/tmp/ccpJSQJS.o: In function `main':
main.cpp:(.text+0x51): undefined reference to `Outside_library::my_const'
collect2: error: ld returned 1 exit status
Can someone please help me understand why the constant is defined when using new, but not when using make_unique?
C++ has something known as the One-Definition Rule (ODR):
Informally, an object is odr-used if its value is read (unless it is a compile time constant) or written, its address is taken, or a reference is bound to it; a reference is odr-used if it is used and its referent is not known at compile time; and a function is odr-used if a function call to it is made or its address is taken. If an object, a reference or a function is odr-used, its definition must exist somewhere in the program; a violation of that is usually a link-time error.
The linked site gives the following example:
struct S {
static const int x = 0; // static data member
// a definition outside of class is required if it is odr-used
};
const int& f(const int& r);
int n = b ? (1, S::x) // S::x is not odr-used here
: f(S::x); // S::x is odr-used here: a definition is required
Your explicit constructor invocation does not "odr-use" Outside_library::my_const but the call to std::make_unique() does. When an object is odr-used it must have exactly one definition (not declaration). Your example has a declaration only. Again from cppreference:
a variable x in a potentially-evaluated expression ex is odr-used unless both of the following are true:
applying lvalue-to-rvalue conversion to x yields a constant expression that doesn't invoke non-trivial functions
either x is not an object (that is, x is a reference) or, if x is an object, it is one of the potential results of a larger expression e, where that larger expression is either a discarded-value expression or has the lvalue-to-rvalue conversion applied to it
The solution as suggested by Jarod42 is to use constexpr instead of const (if you have control over the "outside library" code). If you do not, then you'll need to link the program against the library that contains the definition of Outside_library::my_const.
g++ main.cpp -std=c++14 -lOutside_library
make_unique takes (forwardind) reference of its parameter, and so odr-use it.
My_class(Outside_library::my_const) only use the value.
One solution is to define the member in a TU:
const int Outside_library::my_const;
or using constexpr value (since C++11):
class Outside_library
{
public:
static constexpr int my_const = 100;
};

`static constexpr` function called in a constant expression is...an error?

I have the following code:
class MyClass
{
static constexpr bool foo() { return true; }
void bar() noexcept(foo()) { }
};
I would expect that since foo() is a static constexpr function, and since it's defined before bar is declared, this would be perfectly acceptable.
However, g++ gives me the following error:
error: ‘static constexpr bool MyClass::foo()’ called in a constant expression
This is...less than helpful, since the ability to call a function in a constant expression is the entire point of constexpr.
clang++ is a little more helpful. In addition to an error message stating that the argument to noexcept must be a constant expression, it says:
note: undefined function 'foo' cannot be used in a constant expression
note: declared here
static constexpr bool foo() { return true; }
^
So...is this a two-pass-compilation problem? Is the issue that the compiler is attempting to declare all the member functions in the class before any of them are defined? (Note that outside of the context of a class, neither compiler throws an error.) This surprises me; intuitively, I don't see any reason for static constexpr member functions not to be useable in any and all constant expressions, inside the class or out.
As T.C. demonstrated with some links in a comment, the standard is not quite clear on this; a similar problem arises with trailing return types using decltype(memberfunction()).
The central problem is that class members are generally not considered to be declared until after the class in which they're declared is complete. Thus, regardless of the fact that foo is static constexpr and its declaration precedes that of bar, it cannot be considered "available" for use in a constant expression until MyClass is complete.
As pointed out by Shafik Yaghmour, there is some attempt within the standard to avoid a dependency on the ordering of members within a class, and obviously allowing the example in the original question to compile would introduce an ordering dependency (since foo would need to be declared before bar). However, there is already a minor dependency on ordering, because although constexpr functions can't be called inside noexcept, a noexcept expression itself might depend on an earlier declaration inside the class:
class MyClass
{
// void bar() noexcept(noexcept(foo())); // ERROR if declared here
static constexpr bool foo();
void bar() noexcept(noexcept(foo())); // NO ERROR
}
(Note that this is not actually a violation of 3.3.7, since there is still only one correct program that is possible here.)
This behavior may actually be a violation of the standard; T.C. points out (in a comment below) that foo here should actually be looked up in the scope of the whole class. Both g++ 4.9.2 and clang++ 3.5.1 fail with an error when bar is declared first but compile with no errors or warnings when foo is declared first. EDIT: clang++ trunk-revision 238946 (from shortly before the release of 3.7.0) does not fail when bar is declared first; g++ 5.1 still fails.
Intriguingly, the following variation causes a "different exception specifier" with clang++ but not with g++:
class MyClass
{
static constexpr bool foo2();
void bar2() noexcept(noexcept(foo2()));
};
constexpr bool MyClass::foo2() { return true; }
void MyClass::bar2() noexcept(noexcept(MyClass::foo2())) { }
According to the error, the noexcept specification for the declaration of bar2 evaluates to noexcept(false), which is then considered a mismatch for noexcept(noexcept(MyClasss::foo2())).

static constexpr member function not callable inside non-template class C++ [duplicate]

I have the following code:
class MyClass
{
static constexpr bool foo() { return true; }
void bar() noexcept(foo()) { }
};
I would expect that since foo() is a static constexpr function, and since it's defined before bar is declared, this would be perfectly acceptable.
However, g++ gives me the following error:
error: ‘static constexpr bool MyClass::foo()’ called in a constant expression
This is...less than helpful, since the ability to call a function in a constant expression is the entire point of constexpr.
clang++ is a little more helpful. In addition to an error message stating that the argument to noexcept must be a constant expression, it says:
note: undefined function 'foo' cannot be used in a constant expression
note: declared here
static constexpr bool foo() { return true; }
^
So...is this a two-pass-compilation problem? Is the issue that the compiler is attempting to declare all the member functions in the class before any of them are defined? (Note that outside of the context of a class, neither compiler throws an error.) This surprises me; intuitively, I don't see any reason for static constexpr member functions not to be useable in any and all constant expressions, inside the class or out.
As T.C. demonstrated with some links in a comment, the standard is not quite clear on this; a similar problem arises with trailing return types using decltype(memberfunction()).
The central problem is that class members are generally not considered to be declared until after the class in which they're declared is complete. Thus, regardless of the fact that foo is static constexpr and its declaration precedes that of bar, it cannot be considered "available" for use in a constant expression until MyClass is complete.
As pointed out by Shafik Yaghmour, there is some attempt within the standard to avoid a dependency on the ordering of members within a class, and obviously allowing the example in the original question to compile would introduce an ordering dependency (since foo would need to be declared before bar). However, there is already a minor dependency on ordering, because although constexpr functions can't be called inside noexcept, a noexcept expression itself might depend on an earlier declaration inside the class:
class MyClass
{
// void bar() noexcept(noexcept(foo())); // ERROR if declared here
static constexpr bool foo();
void bar() noexcept(noexcept(foo())); // NO ERROR
}
(Note that this is not actually a violation of 3.3.7, since there is still only one correct program that is possible here.)
This behavior may actually be a violation of the standard; T.C. points out (in a comment below) that foo here should actually be looked up in the scope of the whole class. Both g++ 4.9.2 and clang++ 3.5.1 fail with an error when bar is declared first but compile with no errors or warnings when foo is declared first. EDIT: clang++ trunk-revision 238946 (from shortly before the release of 3.7.0) does not fail when bar is declared first; g++ 5.1 still fails.
Intriguingly, the following variation causes a "different exception specifier" with clang++ but not with g++:
class MyClass
{
static constexpr bool foo2();
void bar2() noexcept(noexcept(foo2()));
};
constexpr bool MyClass::foo2() { return true; }
void MyClass::bar2() noexcept(noexcept(MyClass::foo2())) { }
According to the error, the noexcept specification for the declaration of bar2 evaluates to noexcept(false), which is then considered a mismatch for noexcept(noexcept(MyClasss::foo2())).