I read that since C++11, the conversion from std::basic_ios to bool is required to be explicit. clang allows to assign the result of getline to a bool only after typecasting. What I do not understand is why it accepts the following code:
while( getline(inputfile, newline) )
?
There's one exception, however. If, for some expression e, the declaration bool t(e) is well-formed and in one of the following contexts, the implicit conversion is invoked.
controlling expression of if, while, for
the logical operators !, && and ||
the conditional operator ?:
static_assert
noexcept
In the case of std::basic_ios, it has an explicit bool operator and thus is eligible for the conversion within the while statement.
Take a look at Implicit conversions for more details.
Related
My understanding is that, nullptr could not be converted implicitly to another types. But later I "found" that it could be converted to bool.
The issue is, I can see it being converted to bool on GCC 4.x, but it complains on GCC > 5.X
#include <iostream>
bool f(bool a){
return !a;
}
// Type your code here, or load an example.
int main() {
return f(nullptr);
}
On >5.x I get
<source>: In function 'int main()':
<source>:7:21: error: converting to 'bool' from 'std::nullptr_t' requires direct-initialization [-fpermissive]
return f(nullptr);
^
<source>:2:6: note: initializing argument 1 of 'bool f(bool)'
bool f(bool a){
^
Compiler returned: 1
I couldn't find anything on the release notes of GCC 5.X that would explain that.
Can be observed here:
https://godbolt.org/g/1Uc2nM
Can someone explain why there is a difference between versions and what rule is applied here.
The rule can be found in C++17 [conv.bool]/1:
For direct-initialization, a prvalue of type std::nullptr_t can
be converted to a prvalue of type bool; the resulting value is false.
Initialization of function parameters is copy-initialization , not direct-initialization. If you are not familiar with this topic; initialization contexts in C++ can be divided into these two classes, and there are some operations that can only occur in direct-initialization.
The restriction to direct-initialization was added in C++14, which could explain the difference between g++ versions.
I assume the purpose of this rule is to raise an error for the exact code you've written: a bool is expected and a null pointer constant was provided; testing a null pointer constant for boolean-ness is not very meaningful since it only has one state anyway.
Remember that nullptr is not a pointer; it's a thing that can be implicitly converted to a null pointer if the code explicitly requests such a conversion. The whole reason for adding it was to fix the hack of 0 being used as a null pointer constant, and inadvertently matching some other template or overload.
The code could be:
return f(static_cast<bool>(nullptr));
or perhaps you could add an overload of f that accepts std::nullptr_t.
From what I've read, C++11 no longer supports an implicit conversion to void* for istream/ostream, which could then be implicitly converted to bool, for use in while loops etc. For example:
string test;
while((getline(cin,test)))
{
cout << "received" << endl;
}
cout << "break";
The standard now implements an explicit bool operator, so
while(static_cast<bool>(getline(cin,test)))
would be the new standard supported method. However, in both Visual Studio 2017, and GNU g++ with the -std=c++11 flag, both versions compile perfectly. With no implicit pathway to bool from istream supported by the standard, why is this? I can understand VS playing fast and loose with the standard, but GNU too? Thanks for any insight.
The implicit conversion to void* was removed, but it was replaced by an explicit conversion to bool. Starting in C++11, an explicit cast operator to bool is treated specially. It's known as a "contextual conversion", and can be used implicitly in an expression which naturally expects a boolean value: an if statement condition, a ternary operator's condition, etc.
I have a set of non-orthogonal policies, all of them implementing a common named method, the policies add safety checks.
I want users to be able to combine the policies to allow more complex validation without creating policies for each combination case by hand.
My approach is creating a new policy class to combine others.
The simplified example below shows C as the combining class, here the method id is combined. The expected result is, when calling id on C, to sequentially call the id of each base class.
#include <iostream>
using namespace std;
struct A
{
void id() { cout << "A ";}
};
struct B
{
void id() { cout << "B ";}
};
template<class A, class... As>
struct C : public A, public As...
{
void id()
{
A::id();
As...::id(); // This line does not work, it is illustrative.
}
};
int main()
{
C<A, B> c;
c.id();
//expected: result A B
}
The question is: Is it possible to expand As... somehow to do this without using a recursive approach, just using the ... operator?
Sure. You need a context that permits pack expansion - a simple one is a braced initializer list, which also has the benefit of guaranteeing left-to-right evaluation:
using expander = int[];
(void) expander { 0, ((void) As::id(), 0)... };
... expands a pattern to its left; in this case the pattern is the expression ((void) As::id(), 0).
The , in the expression is the comma operator, which evaluates the first operand, discards the result, then evaluates the second operand, and returns the result.
The (void) cast on As::id() exists to guard against overloaded operator,, and can be omitted if you are sure that none of the As::id() calls will return something that overloads the comma operator.
0 on the right hand side of the comma operator is because expander is an array of ints, so the whole expression (which is used to initialize an element of the array) must evaluate to an int.
The first 0 ensures that we don't attempt to create an illegal 0-sized array when As is an empty pack.
Demo.
In C++17 (if we are lucky), the entire body of C::id can be replaced with a binary fold expression: (A::id(), ... , (void) As::id()); Demo.
This code is not supposed to compile , so why it is ?
what is the principle of the context in if expression ?
class B {
public:
B() {}
explicit operator bool () {}
};
int main (){
B Bp;
//bool check = Bp // error
if (Bp){ //o.k
return 1;
}
return 0;
}
Thanks
That code very much is supposed to compile. The standard expended a very great deal of effort to ensure that it does.
There are a number of places where an expression is "contextually converted to bool" In those places, explicit bool conversions will be called if they're available. One of those contextual conversions is the if expression, as in your case.
This language allows explicit operator bool types to still be used for conditional checking if(expr), but you can't other things without an explicit conversion. You can't pass it to a function that takes a bool; you can't return it from a function that returns bool, and so forth.
All of the contextual conversions are explicit expressions in language features. So explicit operator bool protects you from implicit user-defined conversions, while still allowing language-defined conversions to happen.
can anyone tell me the type of value to which e.g. a==b (or in general any if-statement) evaluates in C? Probably char or int?
In C language, result of Boolean/relational expression is non-zero (true) or zero (false), which is a signed int type.