std::is_same different results between compilers - c++

#include <iostream>
int main() {
bool b = true;
std::cout << std::is_same<decltype(!(!b)), bool>::value << "\n";
auto bb = (!(!b));
std::cout << std::is_same<decltype(bb), bool>::value << "\n";
}
The above code has different results using different compilers.
Is this a compiler bug or am I missing something?
clang 1 1 (https://godbolt.org/z/s43T55rxq)
msvc 1 1 (https://godbolt.org/z/YnKfKh41q)
gcc 0 1 (https://godbolt.org/z/91xdfv93c)

This is a gcc bug. The problem is that gcc incorrectly treats the expression !(!b) as an lvalue instead of rvalue. You can confirm this here. As you'll see in the above linked demo, the output gcc gives is lvalue instead of prvalue.
The bug has been reported as:
GCC treats rvalue as an lvalue

Related

Is it safe to modify and access the same object in a shift operator expression under the new standard? [duplicate]

I read in the C++17 Standard $8.5.7.4:
The expression E1 is sequenced before the expression E2.
for shift operators.
Also cppreference rule 19 says:
In a shift operator expression E1<>E2, every value computation and side-effect of E1 is sequenced before every value computation and side effect of E2
But when I try to compile the following code with gcc 7.3.0 or clang 6.0.0
#include <iostream>
using namespace std;
int main() {
int i = 5;
cout << (i++ << i) << endl;
return 0;
}
I get the following gcc warning:
../src/Cpp_shift.cpp: In function ‘int main()’:
../src/Cpp_shift.cpp:6:12: warning: operation on ‘i’ may be undefined [-Wsequence-point]
cout << (i++ << i) << endl;
~^~
The clang warning is:
warning: unsequenced modification and access to 'i' [-Wunsequenced]
I used the following commands to compile:
g++ -std=c++17 ../src/Cpp_shift.cpp -o Cpp_shift -Wall
clang++ -std=c++17 ../src/Cpp_shift.cpp -o Cpp_shift -Wall
I get the expected 320 as output in both cases ( 5 * 2 ^ 6 )
Can someone explain why I get this warning? Did I overlook something? I also read this related question, but it does not answer my question.
edit: all other variants ++i << i, i << ++i and i << i++ result in the same warning.
edit2: (i << ++i) results in 320 for clang (correct) and 384 for gcc (incorrect). It seems that gcc gives a wrong result if the ++ is at E2, (i << i++) also gives a wrong result.
Standard is clear about the order of evaluation of the operands of the shift operator.
n4659 - §8.8 (p4):
The expression E1 is sequenced before the expression E2.
There is no undefined behavior in the expression i++ << i, it is well defined. It is a bug in Clang and GCC both.

Why MacOS clang can't use C++17 std?

I want to use c++1z in MacOS10.14.4, like this g++ -std=c++1z test.cpp -o test. But the clang can't compile the code.
The error as follows.
In file included from test.cpp:3:
/Library/Developer/CommandLineTools/usr/include/c++/v1/any:599:5: error: static_assert failed due to requirement 'is_constructible<basic_string<char> &&, _RawValueType
&>::value' "ValueType is required to be an lvalue reference or a CopyConstructible type"
static_assert(is_constructible<_ValueType, _RawValueType &>::value,
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:29:19: note: in instantiation of function template specialization 'std::__1::any_cast<std::__1::basic_string<char> &&>' requested here
auto b = std::any_cast<std::string&&>(a); //< rvalue reference (no need for std::move)
^
1 error generated.
But the same code can work on Linux. The code as follows.
#include <string>
#include <iostream>
#include <any>
int main()
{
// simple example
auto a = std::any(12);
std::cout << std::any_cast<int>(a) << '\n';
try {
std::cout << std::any_cast<std::string>(a) << '\n';
}
catch(const std::bad_any_cast& e) {
std::cout << e.what() << '\n';
}
// advanced example
a = std::string("hello");
auto& ra = std::any_cast<std::string&>(a); //< reference
ra[1] = 'o';
std::cout << "a: " << std::any_cast<const std::string&>(a) << '\n'; //< const reference
auto b = std::any_cast<std::string&&>(a); //< rvalue reference (no need for std::move)
// Note, 'b' is a move-constructed std::string, 'a' is now empty
std::cout << "a: " << *std::any_cast<std::string>(&a) //< pointer
<< "b: " << b << '\n';
}
clang version: Apple LLVM version 10.0.1 (clang-1001.0.46.4)
And I use the gcc to compile this code, but didn't work either.
This seems to be from https://developercommunity.visualstudio.com/content/problem/200281/stdany-cast-static-assert-error-because-of-is-cons.html, which has an answer from Microsoft. The answer there was that this was a defect LWG 2768, so the fix may not have been implemented in older implementations of the standard library. For example, this compiles in clang 6.0.0 and gcc 7.4, but not clang 7.0.0 and gcc 8.1.
The reason is that you can't take an rvalue reference of an lvalue any. Fix this by either taking an lvalue reference and moving that or taking an rvalue reference of a moved any:
std::move(std::any_cast<std::string&>(a));
std::any_cast<std::string&&>(std::move(a));

auto template parameters: g++ 7.3 vs clang++ 6.0 : Which compiler is correct?

Two compilers produce different results for this code example.
Clang generates two different types. G++ uses same type for fu and fi.
Which one is standard compliant?
#include <iostream>
template< auto IVAL>
struct foo {
decltype(IVAL) x = -IVAL;
};
int main()
{
foo<10u> fu;
foo<10> fi;
std::cout << fi.x << " " << fu.x << '\n';
return 0;
}
g++-7.3 output:
4294967286 4294967286
clang-6.0 output:
-10 4294967286
gcc is wrong here, these are clearly two distinct types.
And to confirm - this bug is fixed in gcc 8.0.1
Sample code

Is the order for variadic template pack expansion defined in the standard?

I thought that expanding a parameter pack had the following behavior:
// for Args ... p
f(p)...;
// was equivalent to
f(p1); f(p2); ...; f(pn);
But I just found out that gcc (4.6, 4.7 and 4.8) does it the other way around:
f(pn); ...; f(p2); f(p1);
Whereas clang does it as I expected.
Is that a bug in GCC or are they both valid according to the standard?
Minimal example
#include <iostream>
#include <string>
template<typename T>
bool print(const unsigned index, const T& value){
std::cerr << "Parameter " << index << " is " << value << std::endl;
return true;
}
template<typename ... Args>
void printAll(Args ... args){
unsigned i = 0;
[](...){}(print(i++, args)...);
}
int main(){
int a = 1; float b = 3.14; std::string c("hello");
printAll(a, b, c);
}
Compiling and executing:
$> clang++ -std=c++11 -o test test.cpp
$> ./test
Parameter 0 is 1
Parameter 1 is 3.14
Parameter 2 is hello
$> g++ -std=c++11 -o test test.cpp
$> ./test
Parameter 0 is hello
Parameter 1 is 3.14
Parameter 2 is 1
Answer
It didn't take long for Martinho Fernandes to spot the error here. The problem is the order of evaluation of parameters, which is not defined by the standard (1.9.3):
Certain other aspects and operations of the abstract machine are described in this International Standard as
unspecified (for example, order of evaluation of arguments to a function).
Is the order for variadic template pack expansion defined in the standard?
Yes. The expanded elements are in an order that corresponds to the original order of the pack.
In the test, the expansion [](...){}(print(i++, args)...); is equivalent to: [](...){}(print(i++, a), print(i++, b), print(i++, c));.
The test is flawed in that it tests the order of evaluation of function arguments, which is a completely different matter. If you try and execute the expanded form presented above, you will observe the same behaviour. Or you would if the code didn't have undefined behaviour, since the variable i is incremented several times without the increments being sequenced.

No warning on assignment of int to short (gcc)

I often use assignment of "longer" typed variables to "shorter" ones, for example int to short or uint32_t to uint8_t. One day i decided to find all such cases in my code using gcc, but found to my amazement that gcc didn't output any warnings!
int long_value;
short short_value;
std::cin >> long_value; // Example input: 32769
short_value = long_value; // MS Visual Studio complains here at warning level 4
std::cout << "Long: " << long_value << '\n'; // My example output: 32769
std::cout << "Short: " << short_value << '\n'; // My example output: -32767
Using gcc -Wall or gcc -Wconversion didn't help (gcc didn't output any warning). Actually, it never output any warning for any input and output type (e.g. long and unsigned char).
I have never found an actual bug in gcc so i am almost sure this behavior has a reason.
So why no warning?
Update: i use gcc 4.1.2.
This feature was added in gcc 4.3 version. Previously this was not available.
I hope you are using gcc version 4.2 or below.
http://gcc.gnu.org/wiki/NewWconversion confirms this.
This bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=2707 also talks about it.
I can't reproduce that. Compiling this code with gcc 4.4.5 with -Wconversion, I get
a.cc: In function ‘void f()’:
a.cc:7: warning: conversion to ‘short int’ from ‘int’ may alter its value