default behaviour for (bool) cast - c++

classes in the stl, such as unique_ptr will occasionally show examples such as:
// unique_ptr constructor example
#include <iostream>
#include <memory>
int main () {
std::default_delete<int> d;
std::unique_ptr<int> u1;
std::unique_ptr<int> u2 (nullptr);
std::unique_ptr<int> u3 (new int);
std::unique_ptr<int> u4 (new int, d);
std::unique_ptr<int> u5 (new int, std::default_delete<int>());
std::unique_ptr<int> u6 (std::move(u5));
std::unique_ptr<void> u7 (std::move(u6));
std::unique_ptr<int> u8 (std::auto_ptr<int>(new int));
std::cout << "u1: " << (u1?"not null":"null") << '\n';
std::cout << "u2: " << (u2?"not null":"null") << '\n';
std::cout << "u3: " << (u3?"not null":"null") << '\n';
std::cout << "u4: " << (u4?"not null":"null") << '\n';
std::cout << "u5: " << (u5?"not null":"null") << '\n';
std::cout << "u6: " << (u6?"not null":"null") << '\n';
std::cout << "u7: " << (u7?"not null":"null") << '\n';
std::cout << "u8: " << (u8?"not null":"null") << '\n';
*emphasized text* return 0;
}
The line:
std::cout << "u1: " << (u1?"not null":"null") << '\n';
shows the unique_ptr u1 being directly cast to false if it is tracking a null pointer.
I have seen this behaviour used in other custom classes. How is this managed and what operator decides whether a direct cast to bool such as this returns true or false?

It is implemented as a member conversion operator of the form explicit operator bool() const;. Whether it returns true or false is implemented in the logic of the class itself. For example, this class has an bool conversion operator that returns true if it's data member has value 42, and false otherwise:
struct Foo
{
explicit operator bool() const { return n==42; }
int n;
};
#include <iostream>
int main()
{
Foo f0{12};
Foo f1{42};
std::cout << (f0 ? "true\n" : "false\n");
std::cout << (f1 ? "true\n" : "false\n");
}

operator bool();
It's a standard cast-operator to type bool.
Here's an example of how to use it:
class Checked
{
bool state;
public:
Checked(bool _state) : state(_state) { }
explicit operator bool() const {
return state;
}
};
Checked c (true);
if (c)
cout << "true";
Note the explicit keyword. It appeared in C++11 and allows safe conversion of the class to bool, which happens, in short, in the logical context such as if(), while() etc. Without the explicit, bad things could happen, as there's an implicit conversion of bool to numeric types. In C++03 and older it's safer to overload operator ! (), which then is tested as if (!!c).

A conversion operator is used for this functionality:
operator bool(){ return false; }
In C++11 you can also make them explicit
explicit operator bool(){ return true; }
Implicit conversion operators are an error prone endeavour. Consider if unique_ptr had an implicit conversion operator to bool, you could do nonsensical things like...
std::unique_ptr<Thing> x;
int y = 7 + x;
In the above case y would equal 7 + (0 if x is null or 1 if x is non-null)

Related

decltype evaluating the wrong type from an expression list

while experimenting with the answer from This post,
ended up with the following piece of code:
#include <iostream>
#include <typeinfo>
namespace Test
{
struct MyPtr
{
double operator, (int Input)
{
std::cout << "Operator, called" << std::endl;
return 1.0;
}
MyPtr operator* ()
{
std::cout << "operator* called" << std::endl;
return *this ;
}
MyPtr operator++ ()
{
std::cout << "operator++ called" << std::endl;
return *this;
}
MyPtr operator!= (const MyPtr& Other)
{
std::cout << "operator!= called" << std::endl;
return *this;
}
};
struct Foo
{
MyPtr Ptr;
};
MyPtr begin(Foo& t)
{
return t.Ptr;
}
MyPtr end(Foo& t)
{
return t.Ptr;
}
}
int main()
{
std::cout << typeid(decltype(++begin(std::declval<Test::Foo&>()),
*begin(std::declval<Test::Foo&>()),
std::true_type{})).name() <<std::endl;
}
which yields:
d
Here, d comes from the comma operator. However, as the last expression inside the decltype specifier is std::true_type{}, why does the decltype specifier resolves to the type returned by the comma operator instead of std::true type.
My Theory is that std::true_type can be implicitly cast into an int, which operator,() here takes as a parameter, hence the decltype expression is equivalent to:
std::cout << typeid(decltype(++begin(std::declval<Test::Foo&>()),
declval<double&>())).name() <<std::endl;
Can you confirm this is correct?
What i am planning on doing when i will have a better grasp of the compiler's behavior, i plan on replacing the contents of the decltype specifier with:
std::cout << typeid(decltype(void(++begin(std::declval<Test::Foo&>())),
void(*begin(std::declval<Test::Foo&>())),
std::true_type{})).name() <<std::endl;
which will prevent operator,() from matching, even if it is overridden. Can you also confirm this is correct?
I added a member to MyPtr to get more information. Then actually evaluating the expression tells you what happens:
#include <iostream>
#include <typeinfo>
struct MyPtr {
int value;
MyPtr(int x) : value(x) {}
double operator,(int Input) {
std::cout << "Operator, called value = " << value
<< " Input = " << Input << std::endl;
return 1.0;
}
MyPtr operator*() {
std::cout << "operator* called value = " << value << std::endl;
return *this;
}
MyPtr operator++() {
std::cout << "operator++ called value = " << value << std::endl;
return *this;
}
MyPtr operator!=(const MyPtr& Other) {
std::cout << "operator!= called" << std::endl;
return *this;
}
};
struct Foo { MyPtr Ptr; };
MyPtr begin(Foo& t) { return t.Ptr; }
MyPtr end(Foo& t) { return t.Ptr; }
int main() {
Foo f1{10};
Foo f2{20};
++begin(f1), *begin(f2), std::true_type{};
++begin(f1), *begin(f2), std::false_type{};
}
Output:
operator++ called value = 10
operator* called value = 20
Operator, called value = 20 Input = 1
operator++ called value = 10
operator* called value = 20
Operator, called value = 20 Input = 0
Your "Theory" is correct. Lets remove the ++ and * to make it simpler, then you can think of f1,f2,std::true_type{} as f1.operator,( f2.operator,(std::true_type{}). std::true_type has operator bool and bool can be implcicitly converted to int. To illustrate that I also added the example with false_type in the code.
The operator bool can be found here as operator value_type, because std::true_type is just an alias for std::integral_constant<bool,true>.
which will prevent operator,() from matching, even if it is overridden. Can you also confirm this is correct?
Yes. It is not possible to implement an comma operator overload for void.

Missing automatic move of returned local variable

I'm running into an issue where under a specific set of conditions, a local variable being returning by a function is copied instead of moved. So far, it seems like it needs to meet the following:
The returned variable has some usage in the function. I'm assuming otherwise the whole copy/move is ellided.
The returned type is using a perfect forwarding-style constructor. From this answer (Usage of std::forward vs std::move) I learned that this style of constructor has some different deduction rules.
Be compiled in gcc before 8.0. Compiling under clang (and apparently gcc 8.0+, thanks PaulMcKenzie for the comment) produces the results I expect, however I'm not free to change the compiler being used in the larger project.
Here's some minimum reproduction:
#include <iostream>
#include <type_traits>
// Test class to print copies vs. moves.
class Value
{
public:
Value() : x(0) {}
Value(Value&& other) : x(other.x)
{
std::cout << "value move" << std::endl;
}
Value(const Value& other) : x(other.x)
{
std::cout << "value copy" << std::endl;
}
int x;
};
// A container class using a separate lvalue and rvalue conversion constructor.
template<typename T>
class A
{
public:
A(const T& v) : data_(v)
{
std::cout << "lvalue conversion" << std::endl;
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
A(T&& v) : data_(std::move(v))
{
std::cout << "rvalue conversion" << std::endl;
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
T data_;
};
// A container class using a single perfect forwarding constructor.
template<typename T>
class B
{
public:
template <typename U>
B(U&& v) : data_(std::forward<U>(v))
{
std::cout << "template conversion" << std::endl;
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
T data_;
};
// Get a Value rvalue.
Value get_v()
{
Value v;
v.x = 10; // Without this things get ellided.
return v;
}
// Get an A<Value> rvalue.
A<Value> get_a()
{
Value v;
v.x = 10; // Without this things get ellided.
return v;
}
// Get a B<Value> rvalue.
B<Value> get_b()
{
Value v;
v.x = 10; // Without this things get ellided.
return v;
}
int main()
{
Value v = Value();
std::cout << "--------\nA" << std::endl;
std::cout << "lvalue" << std::endl;
A<Value> a0(v);
std::cout << a0.data_.x << std::endl;
std::cout << "rvalue" << std::endl;
A<Value> a1(get_v());
std::cout << a1.data_.x << std::endl;
std::cout << "get_a()" << std::endl;
std::cout << get_a().data_.x << std::endl;
std::cout << "--------\nB" << std::endl;
std::cout << "lvalue" << std::endl;
B<Value> b0(v);
std::cout << b0.data_.x << std::endl;
std::cout << "rvalue" << std::endl;
B<Value> b1(get_v());
std::cout << b1.data_.x << std::endl;
std::cout << "get_b()" << std::endl;
std::cout << get_b().data_.x << std::endl;
return 0;
}
Under gcc this produces:
--------
A
lvalue
value copy
lvalue conversion
A<T>::A(const T&) [with T = Value]
0
rvalue
value move
rvalue conversion
A<T>::A(T&&) [with T = Value]
10
get_a()
value move <---- Works with separate constructors.
rvalue conversion
A<T>::A(T&&) [with T = Value]
10
--------
B
lvalue
value copy
template conversion
B<T>::B(U&&) [with U = Value&; T = Value]
0
rvalue
value move
template conversion
B<T>::B(U&&) [with U = Value; T = Value]
10
get_b()
value copy <---- Not what I expect!
template conversion
B<T>::B(U&&) [with U = Value&; T = Value]
10
For completeness, clang gives:
--------
A
lvalue
value copy
lvalue conversion
A<Value>::A(const T &) [T = Value]
0
rvalue
value move
rvalue conversion
A<Value>::A(T &&) [T = Value]
10
get_a()
value move
rvalue conversion
A<Value>::A(T &&) [T = Value]
10
--------
B
lvalue
value copy
template conversion
B<Value>::B(U &&) [T = Value, U = Value &]
0
rvalue
value move
template conversion
B<Value>::B(U &&) [T = Value, U = Value]
10
get_b()
value move <---- Like this!
template conversion
B<Value>::B(U &&) [T = Value, U = Value]
10
I have two questions:
Is this allowed behavior by gcc?
Is there any way to force move behavior here through changing the implementation of A/B? It seems any time you have a templated function parameter being taken as && it will trigger the special rules for perfect forwarding, so if I try to provide two constructors as in the A example, one taking const U& and one taking U&&, it won't avoid the problem as long as they have other templating in place.

Copy assignment operator for variadic std::tuple

I have a variadic template with a variadic std::tuple as a member.
I declared the default assignment operator.
MSVC complains that the operator is deleted. I can still run the program.
It doesnt give the expected result.
So 3 Questions come to my mind:
Why is the default copy assignment operator not generated even if flagged as default?
Why can I run the programm still with the code posted?
How to declare a assignment operator for std::tuple<T...> template?
#include <string>
#include <iostream>
#include <tuple>
template<typename ...T>
class Variadic
{
public:
explicit Variadic(T... args)
:m_data{ std::move(args)... }
{
}
Variadic& operator=(const Variadic&) = default;
template<typename Type>
Type get_element() const
{
return std::get<Type>(m_data);
}
private:
std::tuple<T...> m_data{};
};
int main()
{
Variadic<int, std::string> tuple1{ 1, "a" };
Variadic<int, std::string> tuple2{ 2, "b" };
std::cout << tuple1.get_element<int>() << '\n'; // 1
std::cout << tuple1.get_element<std::string>() << '\n'; // a
std::cout << tuple2.get_element<int>() << '\n'; // 2
std::cout << tuple2.get_element<std::string>() << '\n'; // b
tuple2 = tuple1; // MSVC2017 gives warning here:
//function "Variadic<T...>::operator=(const Variadic<T...> &) [with T=<int, std::string>]"
//(declared at line 13) cannot be referenced -- it is a deleted function
// still it compiles ???
std::cin.get();
std::cout << tuple1.get_element<int>() << '\n'; // 1
std::cout << tuple1.get_element<std::string>() << '\n'; // a
std::cout << tuple2.get_element<int>() << '\n'; // expect 1 but 2 ?
std::cout << tuple2.get_element<std::string>() << '\n'; // expect b but a ?
}

What causes a move assignment operator to not be called?

I'm working on my own smart pointer and I ran into some weird problems. The move assignment operator was not being called. So I wrote a test class and was able to reproduce the issue. The move assignment operator is not called but a copy assignment occurs (even when there is no copy assignment operator).
This is my test class
#include <utility>
#include <iostream>
struct tag_t {};
constexpr tag_t tag {};
template <typename T>
struct Foo {
Foo() noexcept
: val{} {
std::cout << "Default construct\n";
}
template <typename U>
Foo(tag_t, const U &val) noexcept
: val{val} {
std::cout << "Construct " << val << '\n';
}
~Foo() noexcept {
std::cout << "Destruct " << val << '\n';
}
template <typename U>
Foo(Foo<U> &&other) noexcept
: val{std::exchange(other.val, U{})} {
std::cout << "Move construct " << val << '\n';
}
template <typename U>
Foo &operator=(Foo<U> &&other) noexcept {
std::cout << "Move assign " << other.val << '\n';
val = std::exchange(other.val, U{});
return *this;
}
T val;
};
These are the tests
int main() {
{
Foo<int> num;
std::cout << "Value " << num.val << '\n';
num = {tag, 5};
std::cout << "Value " << num.val << '\n';
}
std::cout << '\n';
{
Foo<int> num;
std::cout << "Value " << num.val << '\n';
num = Foo<int>{tag, 5};
std::cout << "Value " << num.val << '\n';
}
return 0;
}
After running the tests, I get these results
Default construct
Value 0
Construct 5
Destruct 5
Value 5
Destruct 5
Default construct
Value 0
Construct 5
Move assign 5
Destruct 0
Value 5
Destruct 5
What baffles me is the output of the first test. The move assignment operator is not called but a copy assignment takes place. This results in 5 being destroyed twice. Not ideal when you're trying to make a smart pointer!
I'm compiling with Apple Clang with optimizations disabled. Can someone explain my observations? Also, how do I ensure that the move assignment operator is called in the first test?
template <typename U>
Foo &operator=(Foo<U> &&other) noexcept;
this cannot be called by ={ }.
Instead, Foo& operator=(Foo&&)noexcept is called.
Template methods are never special member functions. Explicitly default, delete or implement them.

C++: which constructors are called in vector<int> vn{MyAllocator<int>(a)}?

I have a trivial allocator:
// alloc.h
#include <cstdlib>
#include <new>
#include <iostream>
template <class T>
struct Mallocator {
typedef T value_type;
Mallocator() {
std::cout << "default ctor is called" << std::endl;
}
template <class U> Mallocator(const Mallocator<U>&) {
std::cout << "copy ctor is called" << std::endl;
}
T* allocate(std::size_t n) {
std::cout << "Mallocator::allocate(size_t n) is called, n = " << n << " ";
if(n > std::size_t(-1) / sizeof(T)) throw std::bad_alloc();
if(T *p = static_cast<T*>(std::malloc(n*sizeof(T)))) {
std::cout << "return p = " << std::hex << (uintptr_t)p << std::dec << std::endl;
return p;
}
throw std::bad_alloc();
}
void deallocate(T* p, std::size_t n) {
std::cout << "Mallocator::deallocate(T *p, size_t n) is called, p = " << std::hex << (uintptr_t)p << std::dec << " n = " << n << std::endl;
std::free(p);
}
};
template <class T, class U>
bool operator==(const Mallocator<T>&, const Mallocator<U>&) { return true; }
template <class T, class U>
bool operator!=(const Mallocator<T>&, const Mallocator<U>&) { return false; }
And this is the client code (only one of A, B, C is used):
#include "alloc.h"
#include <vector>
#include <iostream>
using namespace std;
int main() {
Mallocator<int> a;
cout << "---instantiate---" << endl;
// vector<int, Mallocator<int>> v(a); // A
vector<int, Mallocator<int>> v{Mallocator<int>(a)}; // B
// vector<int, Mallocator<int>> v(Mallocator<int>(a)); // C
cout << "---push_back(1)---" << endl;
v.push_back(1);
cout << "---push_back(2)---" << endl;
v.push_back(2);
cout << "---push_back(3)---" << endl;
v.push_back(3);
cout << "---push_back(4)---" << endl;
v.push_back(4);
cout << "---push_back(5)---" << endl;
v.push_back(5);
cout << "---exiting---" << endl;
}
The output, no matter A or B is used, is always this:
default ctor is called
---instantiate---
---push_back(1)---
// omitted for brevity..
My question:
(1) if A is present, the allocator is just constructed once, that's understandable. But when B is present instead of A, apparently the copy constructor of Mallocator is called in B, but the output doesn't reflect this. Why?
(2) If B is present, which constructor of std::vector is called? In this reference, the only constructor that takes an initializer list doesn't look like this. And if I use C instead of B, it won't compile, and the error message of clang++ is not helping..
Eidt: I know this allocator is trivial but it is not the point of this question..
The code of "alloc.h" is adapted from here, at the end of the page.
1) Your "copy constructor" isn't one. A real copy constructor isn't a template. Every class gets a copy constructor implicitly declared if it doesn't declare one itself. Mallocator<int> doesn't declare a real copy constructor, so one gets implicitly declared and defined for you. Since your class is empty, that copy constructor does nothing and prints nothing (and, thanks to the overload resolution rules, is selected to copy the allocator over your constructor template).
2) List-initialization can call non-initializer-list constructors if no initializer-list constructor is viable. B ends up calling the same constructor as A. Your C is a case of the most-vexing-parse.