I was reading code from the cpp-btree library of google (https://code.google.com/p/cpp-btree/) and I came accross that compile-time assert mechanism.
// A compile-time assertion.
template <bool>
struct CompileAssert {
};
#define COMPILE_ASSERT(expr, msg) \
typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
So I understand more or less what it does, if expr is evaluated to false by the compiler it will declare a new type msg that will be a CompileAssert < false > array of size -1 which will trigger a compilation error.
What I don't get is the bool(expr) part, what is this exactly? Some kind of call to the copy constructor of the class bool? (but it's a builtin type so I'm confused)
I though this would be a mechanism to raise a compilation error when expr is not a boolean but actually I managed to compile a short program whit that line
COMPILE_ASSERT("trash",error_compilation_assert);
It compiles just fine with gcc 3.4
So can anyone explain the bool(expr) part of the mechanism?
It's a type conversion. There are 3 main types of type conversions in C++:
Cast notation (C-style cast): (bool) expr
Functional notation (constructor-style cast): bool(expr)
Cast operators (C++-style cast); static_cast<bool>(expr)
Cast notation and functional notation are semantically equivalent (i.e. they both perform the strongest possible conversion, the C-cast), but the scope & precedence of the functional notation is clearer.
It is generally advised not to use them in C++ code and use the specific cast operators (const_cast, static_cast etc.) instead.
So in your code, it's just a way of forcing the value to type bool and enclosing it in parentheses at the same time, so that no operator priority issues arise.
bool(expr) casts expr into a bool.
The first parameter should be some kind of expression, such as a == b. Using a string literal here is useless.
bool(expr) is a function-style cast which converts the expression to a bool. Lots of things convert implicitly to bool, but I guess they wanted an explicit cast to make sure the result is a bool.
If you convert a pointer to a bool, it evaluates to false if it is a NULL pointer, or true otherwise. Your string literal "Trash" decays into a const char * to the first character. As this is not a null pointer, the expression evaluates to true.
bool(expr) tries to convert expr to bool either implicitly or using any user defined conversion operator.
In C++, you can instantiate built-in types with ctor syntax:
bool b1 = bool(true);
bool b2 = bool(b1);
The difference to:
bool b2 = b1;
is that the latter does an implicit conversion to bool. When such an implicit conversion isn't allowed (as in the template typedef), then bool(b1) makes it explicit by creating a temporary bool from b1 and the temporary doesn't have to be converted anymore; it's an actual bool type.
Related
In c++, bool is used to represent Boolean. that is it holds true or false. But in some case we can use bool to represent integers also.
what is the meaning of bool a=5; in c++?
"what is the meaning of bool a=5; in c++?"
It's actually equivalent to writing
bool a = (5 != 0);
"But in some case we can use bool to represent integers also."
Not really. The bool value only represents whether the integer used to initialize it was zero (-> false) or not (-> true).
The other way round (as mentioned in #Daniel Frey's comment) false will be converted back to an integer 0, and true will become 1.
So the original integer value's (or any other expression results like pointers, besides nullptr, or double values not exactly representing 0.0) will be lost.
Conclusion
As mentioned in LRiO's answer, it's not possible to store information other than false or true in a bool variable.
There are guaranteed rules of conversion though (citation from cppreference.com):
The safe bool problem
Until the introduction of explicit conversion functions in C++11, designing a class that should be usable in boolean contexts (e.g. if(obj) { ... }) presented a problem: given a user-defined conversion function, such as T::operator bool() const;, the implicit conversion sequence allowed one additional standard conversion sequence after that function call, which means the resultant bool could be converted to int, allowing such code as obj << 1; or int i = obj;.
One early solution for this can be seen in std::basic_ios, which defines operator! and operator void* (until C++11), so that the code such as if(std::cin) {...} compiles because void* is convertible to bool, but int n = std::cout; does not compile because void* is not convertible to int. This still allows nonsense code such as delete std::cout; to compile, and many pre-C++11 third party libraries were designed with a more elaborate solution, known as the Safe Bool idiom.
No, we can't.
It's just that there's an implicit conversion from integer to boolean.
Zero becomes false; anything else becomes true.
In fact this declaration
bool a=5;
is equivalent to
bool a=true;
except that in the first declaration 5 as it is not equal to zero is implicitly converted to true.
From the C++ Standard (4.12 Boolean conversions )
1 A prvalue of arithmetic, unscoped enumeration, pointer, or pointer
to member type can be converted to a prvalue of type bool. A zero
value, null pointer value, or null member pointer value is converted
to false; any other value is converted to true. For
direct-initialization (8.5), a prvalue of type std::nullptr_t can be
converted to a prvalue of type bool; the resulting value is false.
One more funny example
bool a = new int;
Of course it does not mean that we may use bool to represent pointers. Simply if the allocation is successfull then the returned poimter is not equal to zero and implicitly converted to true according to the quote I showed.
Take into account that till now some compilers have a bug and compile this code successfully
bool a = nullptr;
Though according to the same quote a valid declaration will look like
bool a( nullptr );
And, basically, I would opine that bool b=5 is "just plain wrong."
Both C and C++ have a comparatively weak system of typing. Nevertheless, I'm of the opinion that this should have produced a compile error ... and, if not, certainly a rejected code review, because it is (IMHO) more likely to be an unintentional mistake, than to be intention.
You should examine the code to determine whether b is or is not "really" being treated as a bool value. Barring some "magic bit-twiddling purpose" (which C/C++ programs sometimes are called-upon to do ...), this is probably a typo or a bug.
Vlad's response (below) shows what the standard says will happen if you do this, but I suggest that, "since it does not make human-sense to do this, it's probably an error and should be treated accordingly by the team.
A "(typecast)?" Maybe. A data-type mismatch such as this? Nyet.
I am following the file boost/smart_ptr/detail/operator_bool.hpp and come across the following snippet of code that I do not understand
typedef T * this_type::*unspecified_bool_type;
operator unspecified_bool_type() const // never throws
{
return px == 0? 0: &this_type::px;
}
I write some test codes with XCode and &this_type::px always return 1. Why?
Can some C++ guru share your thoughts?
This is a little trick known as the Safe Bool Idiom.
The problem is that if you write a conversion operator to bool:
operator bool() const;
Then it can be used in some tricky situations, for example: 1 + sharedp with bool getting promoted to int... stupid eh ?
Therefore, the trick is to use a type that can be converted to bool but on which all other operations will provoke an error during compilation. The recommended way is to use a pointer-to-member in the class, and it is typedefed to an explicit name so that error messages are a bit more understandable.
With C++11, this trick is obsolete, because the explicit qualifier can be applied to conversion operator:
explicit operator bool() const { return px; }
much more pleasant, isn't it ?
&this_type::px is a trick used to obtain a boolean value equivalent to true.
Since boost does not use the bool type, but instead does not specifies what it is, it uses a pointer-to-member cast which always return the equivalent representation of true for an existing member (i.e. not nullptr or something cast from 0).
See 4.12:
A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to
member type can be converted to a prvalue of type bool.
The boolean conversion of pointer-to-members always happen in an integral context because there is no cast from pointer-to-member to an integer in C++.
It is not 1, but it is output by ostream as 1 (bool) if you havent switched on boolalpha flag. ostream has no special output operator for member pointers.
I know the ternary operator has some surprising restrictions, but I was a bit baffled that this fails to compile for me:
void foo(bool b)
{
int* ptr = ((b) ? NULL : NULL);
}
Obviously that's the minimum needed to show the problem. The error is:
[BCC32 Error] Unit11.cpp(20): E2034 Cannot convert 'int' to 'int *'
Compiler is the less-than-100%-conforming Embarcadero C++Builder 2010, so a compiler bug is far from impossible...
NOTE: Parens modified to avoid confusion about my intent.
NOTE2: I'd got myself a little confused about how I'd arrived at this construct in the first place, so here's my excuse: I was getting some compilation errors on a line like a = b? c : d, where b, c and d were all complex expressions. To narrow it down, I replaced c and d with NULLs in order to check if b was the culprit. At this point, everything went to hell in a handcart.
NULL is a macro that expands to 0 (or some integral constant expression with a value of 0, for example, (1 - 1)). It's not otherwise "special."
Any integral constant expression with a value of zero is usable as a null pointer constant, which is the reason that int* ptr = 0; is permitted. However, here, the expression is b ? 0 : 0; this is not an integral constant expression (b is not constant); its type is int, which is not implicitly convertible to int*
The workaround would be to explicitly specify that you want a pointer type:
int* const null_int_ptr = 0;
int* ptr = b ? null_int_ptr : null_int_ptr;
The example is a bit contrived, though: usually when one uses the conditional operator, at least one of the arguments is actually a pointer type (e.g. b ? ptr : 0); when one of the operands is a pointer type, the 0 is implicitly converted to that same pointer type and thus the type of the entire conditional expression is the pointer type, not int.
The only case where you can have this "problem" is where a null pointer constant is used as both the second and third operands of the conditional operator, which is rather odd.
Your problem is that on your system NULL is defined to be 0 which is assumed to be an int in the context of the ternary operator. If you static_cast one of the operands to int* it should auto-promote the other one.
But why are using such a construct in the first place?
NULL could be defined as having type int or even long, so the ternary operator has the same type. There's no implicit conversion to the pointer type, so compiler generates an error.
The gotcha here is that there is an implicit conversion from constant integer expression evaluating to zero (the infamous null pointer constant).
Possible solution here is an explicit cast:
int* ptr = b ? (int*) NULL : NULL;
I'd like to have a simple way of checking for an object to be valid. I thought of a simple conversion function, something like this:
operator bool() const { return is_valid; }
Checking for it to be valid would be very simple now
// is my object invalid?
if (!my_object) std::cerr << "my_object isn't valid" << std::endl;
Is this considered a good practise?
In C++03, you need to use the safe bool idiom to avoid evil things:
int x = my_object; // this works
In C++11 you can use an explicit conversion:
explicit operator bool() const
{
// verify if valid
return is_valid;
}
This way you need to be explicit about the conversion to bool, so you can no longer do crazy things by accident (in C++ you can always do crazy things on purpose):
int x = my_object; // does not compile because there's no explicit conversion
bool y = bool(my_object); // an explicit conversion does the trick
This still works as normal in places like if and while that require a boolean expression, because the condition of those statements is contextually converted to bool:
// this uses the explicit conversion "implicitly"
if (my_object)
{
...
}
This is documented in §4[conv]:
An expression e can be implicitly
converted to a type T if and only if
the declaration T t=e; is well-formed,
for some invented temporary variable t
(§8.5). Certain language constructs
require that an expression be
converted to a Boolean value. An
expression e appearing in such a
context is said to be contextually converted to bool and is well-formed
if and only if the declaration bool t(e); is well-formed, for some
invented temporary variable t (§8.5). The effect of either
implicit conversion is the same as performing the
declaration and initialization and then using the temporary
variable as the result of the conversion.
(What makes the difference is the use of bool t(e); instead of bool t = e;.)
The places were this contextual conversion to bool happens are:
the conditions of if, while, and for statements;
the operators of logical negation !, logical conjunction &&, and logical disjunction ||;
the conditional operator ?:;
the condition of static_assert;
the optional constant expression of the noexcept exception specifier;
No, a simple bool conversion operator is not, as you can now make evil comparisions between unrelated types. Generally, yes, a conversion function is a-okay. Just use the right one (safe-bool idiom). I can't explain it any better than the given links.
The original question was
Is this considered a good practise?
The issue with the safe bool conversion was very relevant in practice, but fortunately has now been addressed by the standards.
But the judgement if this approach is appropriate, is a question of design.
By introducing such a "validity check", effectively you are stating that your objects can be in an invalid state. That is, speaking in the terms of computer science, you added a new separate value to the value domain represented by your objects. A so called bottom value
The most prominent example for a value domain with that propery is the pointer. A pointer can refer to various memory locations, but it also can be NULL (invalid).
Thus we need do ask ourselves: does such a bottom value really reflect the nature of the things we want to model with our classes -- and -- do we really need to cover this aspect of the nature within our model?
Experience shows that bottom values tend to be error prone, easy to forget and generally more of a liability than an asset. If you're able to arrange your code in a way that your objects can not be invalid, your code gets simpler, easier to read, to understand and to maintain..
Not only is this valid and doesn't give any warnings even with -Wall:
void* p = false; // actually 'true' doesn't work here
bool b = "Hello, Boolean!";
but also this compatibility rule permits selecting an overloaded function/operator for a wrong type. Let's say you overloaded your operator << for all fundamental types and you forgot to overload the void pointer, then the compiler may select the version that takes bool, or the other way around.
So what is it that makes this compatibility rule more important than the weird (and highly undesirable) side effects with overloaded functions?
(Edit: removed all references to C, they were wrong: the conversion rules are basically the same in C.)
What do you mean by "C can handle this correctly"? C doesn't permit function overloading, so you are guaranteed to have the bool <-> pointer conversion you're complaining about.
Are you asking why this conversion exists?
The first is not actually a conversion bool -> pointer, but is recognizing that the literal false means 0, which is a valid pointer value. That's why it doesn't work with true, and it doesn't work with a bool variable.
The second is because it's nice to be able to write:
if (p)
instead of
if (p != 0)
to check if a pointer holds a null pointer value.
EDIT: Rules from the standard influencing T* p = false;:
A null pointer constant is an integral constant expression prvalue of integer type that evaluates to zero
and
Types bool, char, char16_t, char32_t, wchar_t, and the signed and unsigned integer types are collectively called integral types. A synonym for integral type is integer type.
and
The Boolean literals are the keywords false and true. Such literals are prvalues and have type bool.