Confusing behavior with std::is_constructible and if constexpr [duplicate] - c++

This question already has answers here:
Wrong understanding of 'if constexpr'
(2 answers)
if constexpr(condition) as compile-time conditional
(1 answer)
Closed 1 year ago.
Probably easiest to explain if I show an example:
#include <iostream>
#include <type_traits>
class Unconstructible
{
public:
Unconstructible() = delete;
};
int main()
{
if constexpr (std::is_constructible_v<Unconstructible>)
{
std::cout << "Unconstructible is constructible. What?\n";
// Unconstructible foo;
}
else
{
std::cout << "Unconstructible is not constructible.\n";
}
return 0;
}
This outputs "Unconstructible is not constructible" as expected. If, however, I uncomment the line Unconstructible foo;, I get a compilation error:
1>F:\Programming\C++\CppScratchwork\CppScratchwork\CppScratchwork\CppScratchwork.cpp(48): error C2280: 'Unconstructible::Unconstructible(void)': attempting to reference a deleted function
1>F:\Programming\C++\CppScratchwork\CppScratchwork\CppScratchwork\CppScratchwork.cpp(39): message : see declaration of 'Unconstructible::Unconstructible'
1>F:\Programming\C++\CppScratchwork\CppScratchwork\CppScratchwork\CppScratchwork.cpp(39,5): message : 'Unconstructible::Unconstructible(void)': function was explicitly deleted
1>Done building project "CppScratchwork.vcxproj" -- FAILED.
That's in MSVC using /std:c++17. The same behavior shows up on GCC with -std=c++17 but with differently-worded error messages involving attempting to reference a deleted function.
Why is it even attempting to compile the first part of the if constexpr branch? As far as I can tell, it is correctly able to tell that std::is_constructible_v<Unconstructible> is false.

Related

List initialization returns semicolon error

I'm trying to compile the following C++ code on Visual Studio Code, using the Mac clang compiler.
#include <iostream>
int main() {
int x { 5 };
std::cout << x;
return 0;
}
However, this returns an error, on the line of the list initialization: int x{ 5 };. Specifically, it says I need to insert a semicolon after the x.
I don't get what's wrong with this code, it works fine on an online compiler. How do I fix this?
Running man clang in the Terminal and skimming through, I found this:
The default C++ language standard is gnu++14.
UPDATE: I ran clang++ main.cpp in the compiler and it returned that semicolon error. This isn't a problem with VSCode, so I'll remove that tag.
Here's the error:
main.cpp:3:10: error: expected ';' at end of declaration
int x { 5 };
^
;
1 error generated.

How does std::promise store const types in MSVC, GCC, and Clang?

Recently, I've started using MSVC to compile a code which was always compiled with GCC and Clang. Some piece of this code produces an interesting compilation error (truncated):
C:/data/msvc/14.33.31424-Pre/include\future(311) error C2678: binary '=': no operator found which takes a left-hand operand of type 'const Result' (or there is no acceptable conversion)
<source>(7): note: could be 'Result &Result::operator =(Result &&)'
<source>(7): note: or 'Result &Result::operator =(const Result &)'
Minimal example of this piece of code:
#include <future>
#include <iostream>
struct Result {
int data{0};
};
// getting rid of constness resolves the problem for MSVC
using result_t = const Result;
using promise_result_t = std::promise<result_t>;
auto compute_result(promise_result_t result)
{
Result some_result{10};
result.set_value(std::move(some_result));
}
int main()
{
promise_result_t my_promise;
auto my_future = my_promise.get_future();
std::thread thread(compute_result, std::move(my_promise));
std::cout << "result: " << my_future.get().data;
thread.join();
return 0;
}
Successful compilation with Clang 11: https://godbolt.org/z/o6Ge85rxG
Successful compilation with GCC 12: https://godbolt.org/z/x1rhqhfGT
Error with MSVC 19: https://godbolt.org/z/4jMYhTj3n
It is quite clear that removal of const for std::promise storage solves the problem, but I'm curious if anyone has tried to dive deep into the implementations of std::promise for different compilers.
What might be the difference that allows this code to compile and work using GCC and Clang, yet produce a compilation error when using MSVC? (Operating via pointers on stored data in GCC and Clang?)
Looks like an MSVC issue, reported here:
https://developercommunity.visualstudio.com/t/std::promise-works-incorrectly-for-const/10092031
and linked to the issue on GitHub:
https://github.com/microsoft/STL/issues/2599

What is purpose of using static_cast<void>()? [duplicate]

This question already has answers here:
what is the use of "static_cast<void>" in macro?
(3 answers)
Why cast unused return values to void?
(10 answers)
Closed 4 years ago.
static_cast<void>() is the 'C++ way' of writing void conversion
In the en.cppreference.com website mentioned as discards the value of the expression. In below link four points on Explanation section
http://en.cppreference.com/w/cpp/language/static_cast
Where and Why should we use static_cast<void>()? give a example..
This is a way to tell that it is ok for a variable to be unused suppressing corresponding compiler warning. This approach has been deprecated with introduction of [[maybe_unused]] attribute in C++17.
The usual purpose of casting to void is to “use” the result of a computation. In relatively strict build environments it is common to output warnings, or even errors, when a variable is declared, maybe even written to, but the result is never used. If, in your code, you know you do not need a result somewhere, you can use the static_cast<void> method to mark the result as discarded – but the compiler will consider the variable used then and no longer create a warning or error.
An example:
#include <iostream>
int myFunction() __attribute__ ((warn_unused_result));
int myFunction()
{
return 42;
}
int main()
{
// warning: ignoring return value of 'int myFunction()',
// declared with attribute warn_unused_result [-Wunused-result]
myFunction();
// warning: unused variable 'result' [-Wunused-variable]
auto result = myFunction();
// no warning
auto result2 = myFunction();
static_cast<void>(result2);
}
When compiled with g++ -std=c++14 -Wall example.cpp, the first two function calls will create warnings.
As VTT pointed out in his post, from C++17 you have the option of using the [[maybe_unused]] attribute instead.

Why is g++ not able to compile tuples? [duplicate]

This question already has answers here:
error: ‘i’ does not name a type with auto [duplicate]
(2 answers)
Closed 6 years ago.
#include <iostream>
#include <tuple>
#include <string>
using namespace std;
int main(){
tuple<string, string, string> x;
x = make_tuple("hi", "a", "b");
cout << get<0>(x) << endl << endl;
}
I've been having difficulties with my program, so I wrote a simpler one and even this does not work. I do not understand why there is a problem after reviewing the documentation several times. It also compiles fine on XCode but for some reason breaks down on g++.
Here is the full error message:
test.cpp:6:3: error: use of undeclared identifier 'tuple'
tuple x;
^
test.cpp:6:9: error: unexpected type name 'string': expected
expression
tuple x;
^
test.cpp:7:3: error: use of undeclared identifier 'x'
x = make_tuple("hi", "a", "b");
^
test.cpp:7:7: error: use of undeclared identifier 'make_tuple'
x = make_tuple("hi", "a", "b");
^
test.cpp:8:11: error: reference to overloaded function could not be
resolved; did you mean to call it? cout << get<0>x << endl << endl;
The command I am using is g++ test.cpp
Try #include <string>.
Possibly (depending on your version og gcc) you also need -std=c++11 on the command line.
The tuple is fine; what you're trying to make it a tuple of is not.
You did not #include <string>!
Thus the word "string" means nothing to your compiler, and it has no idea what you want it to do. It can't even tell that you meant it to be a type, so it can't tell that by the word "tuple" you meant "std::tuple". So on, and so forth…

cast operator function compiles fine in g++ but not in other compilers. Why? [duplicate]

This question already has an answer here:
Operator cast, GCC and clang: which compiler is right?
(1 answer)
Closed 6 years ago.
Consider following program:
struct S {
using T = float;
operator T() { return 9.9f; }
};
int main() {
S m;
S::T t = m;
t = m.operator T(); // Is this correct ?
}
The program compiles fine in g++ ( See live demo here )
But it fails in compilation in clang++, MSVC++ & Intel C++ compiler
clang++ gives following errors ( See live demo here )
main.cpp:8:20: error: unknown type name 'T'; did you mean 'S::T'?
t = m.operator T(); // Is this correct ?
^
S::T
main.cpp:2:11: note: 'S::T' declared here
using T = float;
MSVC++ gives following errors ( See live demo here )
source_file.cpp(8): error C2833: 'operator T' is not a recognized operator or type
source_file.cpp(8): error C2059: syntax error: 'newline'
Intel C++ Compiler also rejects this code ( See live demo here )
So, the question is which compiler is right here ? Is g++ incorrect here or other 3 compilers are incorrect here ? What C++ standard says about this ?
[basic.lookup.classref]/7:
If the id-expression is a conversion-function-id, its conversion-type-id is first looked up in the class of the object expression and the name, if found, is used. Otherwise it is looked up in the context of the entire
postfix-expression. In each of these lookups, only names that denote types or templates whose specializations are types are considered. [ Example:
struct A { };
namespace N {
struct A {
void g() { }
template <class T> operator T();
};
}
int main() {
N::A a;
a.operator A(); // calls N::A::operator N::A
}
— end example]
This indicates that the example could be fine, although in the above example, A has previously been declared as a type name, visible to main.
This was discussed in core issue 156, filed all the way back in 1999:
How about:
struct A { typedef int T; operator T(); };
struct B : A { operator T(); } b;
void foo() {
b.A::operator T(); // 2) error T is not found in the context
// of the postfix-expression?
}
Is this interpretation correct? Or was the intent for this to be an
error only if T was found in both scopes and referred to different
entities?
Erwin Unruh: The intent was that you look in both contexts. If you find it only once, that's the symbol. If you find it in both, both symbols must be "the same" in some respect. (If you don't find it, its an error).
So I'd say that Clang is wrong: the intent, as expressed in the wording to some extent, is that we find T, even if only in the class.