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.
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.
This code works in Visual Studio:
typedef struct {
int a;
} data_t;
using datap_t = std::unique_ptr<data_t>;
using MyPair = std::pair<std::string, datap_t>;
int main() {
data_t * pd1 = new data_t();
MyPair p("tst", pd1); // This does not compile in gcc or clang
// MyPair p2("tst", datap_t(pd1)); // This compiles
return 0;
}
But clang and gcc give error:
error: no matching function for call to 'std::pair<const std::basic_string<char>, std::unique_ptr<data_t> >::pair(const char [3], data_t*&)
Here is the ideone to try.
The fact that I can call datap_t(pd1) and it compiles means the constructor is valid, so why is that template does not find a suitable match?
I was looking to add a key-value pair to a map using emplace and that is why I wanted to have this implicit conversion in the first place. Note that like Visual Studio the implicit conversion works for most other types, such as std::string from "raw string".
This answer looks relevant, but it talks about a fixed bug and is very old.
The std::unique_ptr constructor that take a single raw pointer as input is marked as explicit to prevent implicit conversions.
pd1 is a raw pointer. MyPair p("tst", pd1); involves an implicit conversion to std::unique_ptr, which is why the compile fails in Clang and GCC, as it should be. You have to use an explicit conversion instead:
MyPair p("tst", datap_t(pd1));
A better option is to not use the raw pointer at all:
MyPair p("tst", std::make_unique<data_t>());
Clang and GCC are doing the right thing, Visual Studio is not (despite its unique_ptr documentation showing the relevant constructor is explicit).
I recently came across the following code that uses syntax I have never seen before:
std::cout << char('A'+i);
The behavior of the code is obvious enough: it is simply printing a character to stdout whose value is given by the position of 'A' in the ASCII table plus the value of the counter i, which is of type unsigned int.
For example, if i = 5, the line above would print the character 'F'.
I have never seen char used as a function before. My questions are:
Is this functionality specific to C++ or did it already exist in strict C?
Is there a technical name for using the char() keyword as a function?
That is C++ cast syntax. The following are equivalent:
std::cout << (char)('A' + i); // C-style cast: (T)e
std::cout << char('A' + i); // C++ function-style cast: T(e); also, static_cast<T>(e)
Stroustroup's The C++ programming language (3rd edition, p. 131) calls the first type C-style cast, and the second type function-style cast. In C++, it is equivalent to the static_cast<T>(e) notation. Function-style casts were not available in C.
This is not a function call, it's instead a typecast. More usually it's written as
std::cout << (char)('A'+i);
That makes it clear it's not a function call, but your version does the same. Note that your version might only be valid in C++, while the one above work in both C and C++. In C++ you can also be more explicit and write
std::cout << static_cast<char>('A'+i);
instead.
Not that the cast is necessary because 'A'+i will have type int and be printed as an integer. If you want it to be interpreted as a character code you need the char cast.
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.
GCC allows customization of printf specifiers. However, I don't see how I can "teach" it to accept my string class for %s specifier. My string class is a simple wrapper over char pointer and has exactly one member variable (char * data) and no virtual functions. So, it's kind of ok to pass it as-is to printf-like functions in place of regular char *. The problem is that on gcc static analyzer prevents me from doing so and I have to explicitly cast it to const char * to avoid warnings or errors.
My cstring looks something like this:
class cstring
{
cstring() : data(NULL){}
cstring(const char * str) : data(strdup(str)){}
cstring(const cstring & str) : data(strdup(str.data)){}
~cstring()
{
free(data);
}
...
const char * c_str() const
{
return data;
}
private:
char * data;
};
Example code that uses cstring:
cstring str("my string");
printf("str: '%s'", str);
On GCC I get this error:
error: cannot pass objects of non-trivially-copyable type 'class cstring' through '...'
error: format '%s' expects argument of type 'char*', but argument 1 has type 'cstring' [-Werror=format]
cc1plus.exe: all warnings being treated as errors
The C++ standard doesn't require compilers to support this sort of code, and not all versions of gcc support it. (https://gcc.gnu.org/onlinedocs/gcc/Conditionally-supported-behavior.html suggests that gcc-6.0 does, at least - an open question whether it will work with classes such as the one here.)
The relevant section in the C++11 standard is 5.2.2 section 7:
When there is no parameter for a given argument, the argument is passed in such a way that the receiving function can obtain the value of the argument by invoking va_arg ...
Passing a potentially-evaluated argument of class type (Clause 9)
having a non-trivial copy constructor, a non-trivial move constructor,
or a non-trivial destructor, with no corresponding parameter, is
conditionally-supported with implementation-defined semantics.
(But look on the bright side: if you get into the habit of using c_str, then at least you won't get tripped up when/if you use std::string.)