Is std::transform_reduce without execution policy portable? - c++

I can compile the following code (using std::transform_reduce) with gcc 9.2.1 on both Fedora and Ubuntu, but attempting to compile on clang see godbolt fails, and I've got a report that some FSF version of gcc 9.2.1 also refuses to compile the code, requiring a std::execution_policy as the first argument to the std::transform_reduce.
#include <vector>
#include <algorithm>
#include <numeric>
auto brokenvector(std::vector<int> const& a, std::vector<int> const& b)
{
return std::transform_reduce(cbegin(a), cend(a), cbegin(b), 0, std::plus<>{},std::multiplies<>{});
}
I specifically cannot use a std::execution_policy here, and both cppreference and the C++ draft standard document n4659 show overloads without an execution policy.
Have I stepped into some kind of political minefield where half of the available compilers refuse to implement the standard, or is the code incorrect?

This is a libstdc++ vs libc++ issue. libc++ implements the function and you can see it working with clang on godbolt using -stdlib=libc++ in this live example. gcc implements it now in trunk, but the currently released versions do not. The function was added in this commit.

Related

cmath error on MacOS c++17: call to abs ambiguous

Having this error using c++17 on Mac OS.
As far as I can tell, code is correct and should work fine (compiles without issue w/ g++ and clang++ on linux).
Also, as far as I can tell, the current default mac version of clang [10.0.1] should support c++17 (full version info printout below).
So, my question is: is this actually a bug in my code, but it works by fluke on linux? Or is it an issue with MacOS clang e.g., not full c++17 implementation?
From cppref:
Defined in header (since C++17):
int abs( int n );
Other c++17 features seem to work completely fine.
#include <cmath>
// #include <cstdlib> //works if included
int main() {
int i = 1;
// return std::abs(1); // Works fine
return std::abs(i); // Fails
}
Compile with:
clang++ -std=c++17 test.cpp
Get this error:
test.cpp:7:10: error: call to 'abs' is ambiguous
return std::abs(i);
^~~~~~~~
/Library/Developer/CommandLineTools/usr/include/c++/v1/math.h:761:1: note:
candidate function
abs(float __lcpp_x) _NOEXCEPT {return ::fabsf(__lcpp_x);}
^
(... etc.)
1 error generated.
If you #include <cstdlib>, it works without error.
using -std=gnu++17 or -std=c++1z doesn't remove the problem either.
In the actual code (which is obviously more complex than the above, and actually uses c++17 features), the error happens depending on the order of my include files.
I can't replicate that in the simple example, but I assume it boils down to calling the cstdlib version instead of the cmath version.
Currently, my 'workaround' is to just put the header includes into the order that works..but this is hardly a long-term solution.
Does anyone know the cause?
Version info (error not specific to this MacOS version, also happens on my students' laptops):
Bens-iMac:test ben$ clang++ -v
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.5.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
See LWG Issue 2912
This has been fixed in libc++ trunk. I don't know if Apple has shipped this fix yet. As you found, including <cstdlib> is a workaround.

C++ Complex library compile error

Here is my code:
#include <iostream>
#include <iomanip>
#include <complex>
#include <cmath>
int main()
{
using namespace std::complex_literals;
std::cout<< std::fixed<<std::setprecision(1);
std::complex<double> z1= 1i *1i; //imaginary unit squared
std::cout<<"i * i= " <<z1 <<'\n';
std::complex<double> z2=std::pow(1i, 2); //imaginary unit squared
std::cout <<"pow(i,2) =" <<z2 <<'\n';
}
I compile with gcc hello.cpp -lstdc++ -o hello.o
Basically it won't let me double the powers of a complex number when i do std::complex z2=std::pow(1i, 2);..
I get the following error
error: no matching function for call to 'pow(complex int, int)'
std::complex z2=std::pow(1i, 2);
However, if i remove the complex number and do std::complex z2=std::pow(2, 2);
it returns 4, the correct answer..
There are many more lines of compile errors, but i made it brief
This answer follows up the comments to the original question:
you have to force the compiler to use the c++14 standard with the -std=c++14 option because the literal operator""i is part of the C++14 spec.
GCC uses c++14 by default since version 6.1. Check your compiler version with gcc -v and refer to this link for GCC standard support.
EDIT:
I was able to reproduce the compiling issue with GCC 6.3 through the link provided by Mr Richard Critten in the comments to the original question, who was the first to point to the correct answer. My apology because I totally overlooked the reference to the C++14 standard.
Anyway, for the sake of clarity, I'm editing this answer, because I've found something that may be interesting to share.
The reason why compiling with GCC 6.3 fails is the fact that the reference standard has been changed in December 2016 from C++14 to GNU++14, see here.
GNU++14 is an extension to the C++ standard, that, among other things, provides additional functions overload for standard APIs.
I've found that with GNU++14 SFINAE fails in finding a proper overload for the std::pow() functions unless the type is explicitly set in the template call like in the snipped below:
std::complex<double> z2=std::pow<double>(1i, 2);
The GNU++14 includes changes to the cmath and complex header files, that I believe are the cause of the issue.
Turning on the C++14 flag, that is not the default anymore, fixes the problem.
I don't know why it is not compiling on your system, it runs fine on mine.
I think something is wrong with your compiler. And, not the version. yet you could try std::cout << __cplusplus. See what this prints.
C++11 doesn't recognize std::complex_literals, so doubt that is the case, but yet the compiler still couldn't find the function.
I honestly don't understand why it is searching for (complex int, int). The compiler is either corrupt or an old beta version.
You should either download a fresh version of the compiler or run it online somewhere. Try adding -std=c++14, but I doubt that would help.
Try your code here(it works):
https://www.jdoodle.com/online-compiler-c++14
So, I installed Microsoft Visual Studio.. I am using the clang compiler and my program ran smoothly with no errors!
Thanks for all the help guys, but i think clang is a better c++ compiler

Clang, std::next, libstdc++ and constexpr-ness

Take the following code:
#include <array>
constexpr std::array<int, 10> a{};
static_assert(std::next(std::begin(a)) == std::begin(a) + 1);
With -std=c++17 GCC compiles it flawlessly, but Clang complains that the expression is not an integral constant expression. It looks like that the problem is about the std::next which, however, should be constexpr in C++17.
Nevertheless, std::next is in the std library, not in the compiler itself, therefore there is something weird going on. And just to make things even better, the example compiles perfectly if you pass -stdlib=libc++ to Clang.
What is going on? Who is wrong and who is right?
EDIT
The issue seems to be related to clang being toolchain-ed against GCC 7.2 inside godbolt. If you add the --gcc-toolchain=/opt/compiler-explorer/gcc-snapshot parameter to the command line, everything works flawlessly. (Thanks to #einpoklum who reported the issue to godbolt -- I have been slower ;) )
EDIT
For everyone who consider that an old compiler should work for actual standard, sorry to say that the consideration is meaningless. I am talking about the last versions of both GCC and Clang. And the problem is reproducible with the trunk version of both. Older compilers are not relevant for this question (MSVC behaviour would be interesting, instead).
Compiling in Wandbox
#include <array>
int main()
{
constexpr std::array<int, 10> a{};
static_assert(std::next(std::begin(a)) == std::begin(a) + 1);
}
with clang++ 4.0.1 and command line
clang++ prog.cc -Wall -Wextra -std=c++1z
I get the error
prog.cc:6:18: error: static_assert expression is not an integral constant expression
static_assert(std::next(std::begin(a)) == std::begin(a) + 1);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cc:6:18: note: non-constexpr function 'next<const int *>' cannot be used in a constant expression
/opt/wandbox/clang-4.0.1/include/c++/v1/iterator:599:1: note: declared here
next(_InputIter __x,
^
1 error generated.
But compiling with clang++ 5.0.0 (or 6.0.0 or 7.0.0 HEAD) with
clang++ prog.cc -Wall -Wextra -std=c++17
So it seems a low support for C++17 in clang++ 4.0.1 (and/or libraries used by clang++), corrected in the following versions.
-- EDIT --
The problem is confirmed (see einpoklum's answer) for clang++ 5.0.0 and clang++ 6.0.0 in gobold.
So I suppose the problem is the version of libstdc++: seems that gobold is using a version (a older one, I suppose) where std::next() isn't defined as constexpr where wandbox is using a version where std::next() is constexpr.
With the Clang 6.0.0 and 5.0.0 version on GodBolt.org, your code does indeed fail to compile. But - with clang 5.0.0-3 on my system (Lubuntu 17.10), it seems to compile without errors.
This is weird behavior. So, perhaps not the best possible answer to your question, but faced with something like this I would report it on bugs.llvm.org and see what the clang/LLVM developers say.

'default_random_engine' is not a member of std

I have found many questions to this topic but all problems seem to be related to not compiling with C++ 11. My code is
#include <random>
int main(int argc, char *argv[]){
std::default_random_engine generator;
return 0;
}
even though I compile with
gcc -std=c++0x testmain.cpp
Giving the error that default_random_engine is not a member of std. The program is compiled on a remote machine, which I do not maintain myself but
gcc -v
yields a version of 4.4.7.
Any ideas?
For others:
Check if you actually include random with #include <random>. I didn't have it and some other header included it previously. Now that header got updated and I got this error and didn't find it for a while because I was checking compiler settings.
As DevSolar already stated, your gcc version is too old, to support this C++11 feature.
It was added in gcc-4.5:
Improved experimental support for the upcoming ISO C++ standard,
C++0x, including:
Support for <future>, <functional>, and <random>.
Reference: https://gcc.gnu.org/gcc-4.5/changes.html
This is also reflected by the libstdc++ API Reference: https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-api-4.5/a01118.html
where you can find the following:
typedef minstd_rand0 default_random_engine
Your code works fine for me in: gcc-5.1.0, gcc-4.9.2 and clang-3.7.0,
Also you should use the command: g++ instead of gcc so gcc links against proper c++ libraies by default.
Your problem is you're not compiling with C++11. ;-) (Sorry, could not resist.)
GCC 4.4.7 is dated March 2012. C++11 support was not yet complete in that version.
As of the time of this writing, the current version of GCC is 5.2.0... which is C++14 compliant. Time to update your compiler. ;-)
I hate to recommend this but in your case (old untouchable machine) I can offer a suggestion. The tr1 version of the random library should be available for g++-4.4:
#include <tr1/random>
int main(int argc, char *argv[]){
std::tr1::default_random_engine generator;
return 0;
}
There have been improvements in the std version relative to tr1 version but you should be able to use most <random> features.
You don't even need C++0x.

g++ -- missing array header

The following simple code can't be compiled by g++ 4.3:
#include <array>
using namespace std;
int main()
{
std::array<int, 8> myarray;
return 0;
}
array: No such file or directory
Also, the compiler doesn't seen to understand option '-std=c++11' as is recommended to provide to the compiler. Is there another option?
Thanks.
GCC 4.3 and presumably also your C++ library are too old for the support you're looking for. You need a newer version. Here's a link to the GCC C++11 support page, and another link to the libstdc++ C++11 support page.
Alternatively, clang supports all of C++11 with libc++.
For me the problem was that it was a cross compiler that needed to be told where the sysroot was, and supplying --sysroot=<path to sysroot> allowed GCC to find the headers