constexpr works on Ubuntu, but not MacOS - c++

I have this code which compiles fine on Ubuntu, but when I try to compile it on MacOS I get this error:
Constexpr variable 'HeuristicNames' must be initialized by a constant expression
#define LSHPair std::pair<const char *, LISTSCHED_HEURISTIC>
static constexpr LSHPair HeuristicNames[] = {
LSHPair("CP", LSH_CP), LSHPair("LUC", LSH_LUC),
LSHPair("UC", LSH_UC), LSHPair("NID", LSH_NID),
LSHPair("CPR", LSH_CPR), LSHPair("ISO", LSH_ISO),
LSHPair("SC", LSH_SC), LSHPair("LS", LSH_LS),
LSHPair("LLVM", LSH_LLVM)};
LISTSCHED_HEURISTIC is an enum.
I take this error to mean that some part of the right hand side of the assignment is not a constexpr, so the resulting variable can't be a constexpr. However I don't have a firm enough grasp of the rules around constexpr to understand why, or how to fix it.
I also don't get why this is different on MacOS than on Ubuntu. Can anyone shed some light on this?

First of all you do not need macro.
You could define type
using LSHPair = std::pair<const char *, LISTSCHED_HEURISTIC>;
Or just use brace initialization, what is much more clean:
using LSHPair = std::pair<const char *, LISTSCHED_HEURISTIC>;
static constexpr LSHPair HeuristicNames[] = {
{"CP", LSH_CP},
{"LUC", LSH_LUC},
{"UC", LSH_UC},
{"NID", LSH_NID},
{"CPR", LSH_CPR},
{"ISO", LSH_ISO},
{"SC", LSH_SC},
{"LS", LSH_LS},
{"LLVM", LSH_LLVM}
};
As #CuriouslyRecurringThoughts point out constructor of std::pair is a constexpr since c++14.
I've test this on my Mac OS and apparently clang there works a bit differently then on Linux (as shown on compiler explorer):
Marek R$ g++ main.cpp -std=c++11
main.cpp:17:26: error: constexpr variable 'HeuristicNames' must be initialized by a constant expression
static constexpr LSHPair HeuristicNames[] = {
^ ~
main.cpp:18:5: note: non-constexpr constructor 'pair<char const (&)[3], LISTSCHED_HEURISTIC, false>' cannot be used in a constant expression
{"CP", LSH_CP},
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/utility:446:5: note: declared here
pair(_U1&& __u1, _U2&& __u2)
^
1 error generated.
Marek R$ g++ main.cpp -std=c++14
Marek R$
So MacOS clang is right.
Problem must be on header files and versioning them depending on C++ standard.
Most probably same header files of standard library are used for clang and gcc are used on Linux. On Mac std::pair constructor is prefixed by macro _LIBCPP_CONSTEXPR_AFTER_CXX11 which definition changes deeding on C++ standard enabled. On Linux you have to check by yourself how it is done.

Related

C++ Protocol Buffer: Temporary of non-literal type 'google::protobuf::internal::CallOnInitializedMutex <std::mutex>' in a constant expression

I'm using the protoc-3.18.0-win32 version from here. After successfully compiling the .proto files, I get the following error in my QtCreator 5 (C++11) program:
C:\Users\MyName\MyProject\lib\include\google\protobuf\stubs\mutex.h:124: error: temporary of non-literal type 'google::protobuf::internal::CallOnceInitializedMutex<std::mutex>' in a constant expression
In file included from lib\include/google/protobuf/descriptor.h:66:0,
from lib\include/google/protobuf/message.h:121,
from lib\include/google/protobuf/generated_message_bases.h:42,
from src/protodata/myfile.pb.h:26,
from src/myfile/myfile.h:12,
from src\myclass/myclass.h:8,
from src\mywidget.cpp:2:
lib\include/google/protobuf/stubs/mutex.h: In constructor 'constexpr google::protobuf::internal::WrappedMutex::WrappedMutex()':
lib\include/google/protobuf/stubs/mutex.h:124:29: error: temporary of non-literal type 'google::protobuf::internal::CallOnceInitializedMutex<std::mutex>' in a constant expression
constexpr WrappedMutex() {}
^
lib\include/google/protobuf/stubs/mutex.h:98:7: note: 'google::protobuf::internal::CallOnceInitializedMutex<std::mutex>' is not literal because:
class CallOnceInitializedMutex {
^~~~~~~~~~~~~~~~~~~~~~~~
lib\include/google/protobuf/stubs/mutex.h:98:7: note: 'google::protobuf::internal::CallOnceInitializedMutex<std::mutex>' has a non-trivial destructor
where the erroneous lines of code are:
// Mutex is a natural type to wrap. As both google and other organization have
// specialized mutexes. gRPC also provides an injection mechanism for custom
// mutexes.
class GOOGLE_PROTOBUF_CAPABILITY("mutex") PROTOBUF_EXPORT WrappedMutex {
public:
#if defined(__QNX__)
constexpr WrappedMutex() = default;
#else
constexpr WrappedMutex() {} // <--- Error points here
#endif
I hit the same issue when trying to use protobuf version higher than 3.15.0 with gcc 7.3 and c++17. This turned out to be a gcc bug, see more in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82461.
After looking into the protobuf generated code, what i find is in version after 3.15, protobuf generated code container pervasive 'constexpr' which trigger the gcc bug.
Possible solution:
use higher version of gcc, the bug is fixed in 7.4 (preferred)
use '-std=c++14' instead of '-std=c++17', this works for me
use protobuf older than 3.15, 3.13 and 3.14 works for me.
In my case it was enough:
Go to your opencv folder, find the file \opencv\sources\3rdparty\protobuf\src\google\protobuf\stubs\mutex.h and delete the line after the first else at the WrappedMutex class,
class GOOGLE_PROTOBUF_CAPABILITY("mutex") PROTOBUF_EXPORT WrappedMutex {
audience:
#if defined(__QNX__)
constexpr WrappedMutex() = default;
#else
constexpr WrappedMutex() {} // **Delete this line**
#endif

What is the correct way to call std::to_chars?

I am trying to call std::to_chars on a double. My code doesn't compile on any compiler I have (gcc 10.2, clang 10.0.1).
Minimally reproducible code (or on godbolt):
#include <charconv>
#include <string>
int main() {
std::string str;
str.resize(30);
auto[ptr, ec] = std::to_chars(str.data(), str.data() + str.size(), double(3.5));
}
I compiled with -std=c++17.
The error I'm getting is:
On gcc 10.2:
<source>: In function 'int main()':
<source>:7:83: error: call of overloaded 'to_chars(char*, char*, double)' is ambiguous
7 | auto[ptr, ec] = std::to_chars(str.data(), str.data() + str.size(), double(3.5));
| ^
In file included from <source>:1:
/.../gcc-10.2.0/include/c++/10.2.0/charconv:366:1: note: candidate: 'std::to_chars_result std::to_chars(char*, char*, char, int)'
...
and then it lists all candidates.
On clang 10.0.1, it pretty much just tells me:
<source>:7:21: error: no matching function for call to 'to_chars'
auto[ptr, ec] = std::to_chars(str.data(), str.data() + str.size(), double(3.5));
^~~~~~~~~~~~~
I tried all the overloads with double that are listed on cppreference's page on std::to_chars, they all give different errors, but in the end nothing works.
I do not understand why the overload resolution is not clear when it should be clear, or am I doing something fundamentally wrong here?
I want to add that MSVC does it fine without any errors.
Your use is perfectly fine, and it compiles correctly under MSVC 19. As described in the Microsoft Docs for the <charconv> functions, this requires at least C++17.
As you can see for yourself in The GNU C++ Library Manual, Chapter 1. Status, C++ 2017, the last update regarding P0067R5 (Elementary string conversions, revision 5) was on GCC 8.1, with the comment "only integral types supported".
Similarly, the libc++ C++17 Status, defines P0067R5 as "Partially done".
If you need more evidence that this is a problem with your C++ implementation, look at the include file for your GCC/Clang installation and you will see that it doesn't define the floating-point overloads (they aren't defined for me, with GCC 10.2.1).

constexpr unique id, compiles with clang but not with gcc

Morning, folks!
I'm refactoring an event queue. I'm poking around to see if I can make event ids unique at compile time. What I've come up with works with clang 4.0.0, but gives a compile error with g++ 6.3.1.
The idea is to use the address of a static member variable to uniquely identify individual types, then use tagging to generate these unique types from a class template.
Using the address of a static member as a type id is a reasonably common technique, but using templates to do it means being clear of the ODR. MSN cites the standard here to suggest that this is a valid approach:
Compile-time constant id
My problem is doing this constexpr. If I remove constexpr and test this at runtime, everything works as expected. Doing this constexpr, however, fails a static assert in g++ saying, "error: non-constant condition for static assertion".
After researching quite a bit, it seems the most similar problems are:
Pointer arithmetic or calling non-constexpr members: Why is this not a constant expression?
There is no pointer arithmetic, everything is constexpr.
Using reinterpret_cast in a constexpr expression: Constexpr pointer value
This is using pointers, but the types are verbatim; so no conversions are applied.
Using incomplete types: Why is this constexpr static member function not seen as constexpr when called?
I'm reasonably sure this type is complete.
Most of these problems are g++ being nonconforming and clang++ erroring out. This is the opposite.
I'm stumped. Here's a stripped-down version of what I've got, annotated with what doesn't compile in g++ in the static asserts:
template <typename tag>
struct t
{
constexpr static char const storage{};
};
template <typename tag>
constexpr char const t<tag>::storage;
struct tag_0 {};
struct tag_1 {};
static_assert(&t<tag_0>::storage == &t<tag_0>::storage, "This always compiles.");
static_assert(&t<tag_1>::storage == &t<tag_1>::storage, "So does this.");
static_assert(&t<tag_0>::storage != &t<tag_1>::storage, "This does not compile with g++.");
static_assert(!(&t<tag_0>::storage == &t<tag_1>::storage), "Neither does this.");
constexpr auto id_0 = &t<tag_0>::storage; // This does.
constexpr auto id_1 = &t<tag_1>::storage; // This does.
static_assert(id_0 != id_1, "This also does not.");
And here are the compiler outputs:
~$ clang++ --version
clang version 4.0.0 (tags/RELEASE_400/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
~$ clang++ -std=c++14 -c example.cpp
~$ g++ --version
g++ (GCC) 6.3.1 20170306
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
example.cpp:14:1: error: non-constant condition for static assertion
static_assert(&t<tag_0>::storage != &t<tag_1>::storage, "This does not compile with g++.");
^~~~~~~~~~~~~
example.cpp:14:34: error: ‘((& t<tag_0>::storage) != (& t<tag_1>::storage))’ is not a constant expression
static_assert(&t<tag_0>::storage != &t<tag_1>::storage, "This does not compile with g++.");
~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~
example.cpp:15:1: error: non-constant condition for static assertion
static_assert(!(&t<tag_0>::storage == &t<tag_1>::storage), "Neither does this.");
^~~~~~~~~~~~~
example.cpp:15:15: error: ‘((& t<tag_0>::storage) != (& t<tag_1>::storage))’ is not a constant expression
static_assert(!(&t<tag_0>::storage == &t<tag_1>::storage), "Neither does this.");
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
example.cpp:19:1: error: non-constant condition for static assertion
static_assert(id_0 != id_1, "This also does not.");
^~~~~~~~~~~~~
example.cpp:19:20: error: ‘((& t<tag_0>::storage) != (& t<tag_1>::storage))’ is not a constant expression
static_assert(id_0 != id_1, "This also does not.");
~~~~~^~~~~~~
~$
I'm curious why this specific approach doesn't compile with gcc, but does with clang, because this conflicts with how I understand constexpr.
(I'm not asking if this is a good design, or if there are other ways to accomplish this. I have other ways to accomplish this.)
Thanks!
EDIT: A comparable example without templates that does compile with both compilers might be:
struct t1
{
static constexpr int const v{};
};
constexpr int t1::v;
struct t2
{
static constexpr int const v{};
};
constexpr int t2::v;
static_assert(&t1::v != &t2::v, "compiles with both");
You're trying to compare two distinct pointers to class members as constexpr and it isn't specified in standard, if compiler should evaluate it as constexpr (addresses of objects might not be yet known?). MSVC and clang does that, gcc doesn't. The result for comparision of pointer to itself is defined.

boost::multiprecision::float128 and C++11

I'm trying to use boost::multiprecision::float128 (boost 1.55.0) under C++11 (gcc 4.8.1), but get the following compiler error:
/cm/shared/apps/boost/gcc/1.55.0/include/boost/multiprecision/float128.hpp: In static member function ‘static std::numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ET> >::number_type std::numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ET> >::min()’:
/cm/shared/apps/boost/gcc/1.55.0/include/boost/multiprecision/float128.hpp:533:55: error: unable to find numeric literal operator ‘operator"" Q’
static number_type (min)() BOOST_NOEXCEPT { return 3.36210314311209350626267781732175260e-4932Q; }
Can't I use boost::multiprecision::float128 in C++11? Or how else do I get it working?
edit
Just to clarify. This error is generated by
#include <boost/multiprecision/float128.hpp>
The compiler is not happy with the statement
return 3.36210314311209350626267781732175260e-4932Q;
in particular the Q is confusing it. I used the compiler flags -std=c++11 -fabi-version=0 -march=native -mfpmath=sse
It looks like a known issue. Try compiling with -fext-numeric-literals.

Invalid conversion to non-const reference in C++0x... bug in std::pair?

I have been developing a library that is getting pretty large, and now I am adding some template-based parts that use C++0x features. So I tried to compile my library (which compiled entirely without warnings on the current standard) with the flag -std=c++0x using gcc version 4.4.5 (on Linux). Now I got a huge influx of error messages related to the conversion of "temporaries" variables to non-const references. The problem is, they are not temporary!
Here is a small piece of code that reproduces the error:
#include <iostream>
#include <map>
struct scanner {
scanner& operator &(std::pair<std::string, int&> i) {
std::cout << "Enter value for " << i.first << ": ";
std::cin >> i.second;
return *this;
};
};
struct vect {
int q[3];
void fill(scanner& aScan) {
aScan & std::pair<std::string, int&>("q0",q[0])
& std::pair<std::string, int&>("q1",q[1])
& std::pair<std::string, int&>("q2",q[2]);
};
};
int main() {
vect v;
scanner s;
v.fill(s);
return 0;
};
If you compile this with the current standard (no c++0x flag) it will compile and run as expected. However, if you compile it with -std=c++0x, it will throw the following error at compile-time:
/usr/include/c++/4.4/bits/stl_pair.h:94: error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘int’
I really can't figure this out. I have looked over the web and SO, but none seem to have this problem. Is it a bug in std::pair? I would really like to know what the problem is.. thank you for any insight you can give.
PS: don't complain about the "quality" or "stupidity" of the code above, it is not real code.. just an example that shows the error.
Your code is not valid C++03, comeau gives (after adding a return statement to op&):
"stl_pair.h", line 44: error: qualifiers dropped in binding reference of
type "int &" to initializer of type "const int"
pair(const _T1& __a, const _T2& __b) : first(__a), second(__b) {}
^
detected during instantiation of "std::pair<_T1, _T2>::pair(const
_T1 &, const _T2 &) [with _T1=std::string, _T2=int &]" at
line 17 of "ComeauTest.c"
...
The problem is a reference inside a pair. If I remember correctly, it is a gcc extension that allows this. Gcc does accept it with -std=gnu++98, which is the default for C++, but with -std=c++98, gcc 4.4.3 gives:
In file included from /usr/include/c++/4.4/bits/stl_algobase.h:66,
from /usr/include/c++/4.4/algorithm:61,
from PREAMBLE:7:
/usr/include/c++/4.4/bits/stl_pair.h: In instantiation of ‘std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, int&>’:
<input>:5: instantiated from here
/usr/include/c++/4.4/bits/stl_pair.h:83: error: forming reference to reference type ‘int&’
...
There are LOTS of bugs in gcc C++0x support, it's very much unfinished and development is ongoing. This is doubly true for a version as old as gcc-4.4.5. If you're serious about starting C++0x development before the standard is ratified, you need to use the bleeding-edge version of the compiler and standard library.
It compiles fine both with and without -std=c++0x with GCC 4.5.2.
I guess GCC 4.4.5 doesn't support C++0x that much to get this working.
Except for the missing return *this; in scanner& operator &(std::pair<std::string, int&> i), your code is valid C++0x.