C++17 "any_cast" fail for implicit ctor, throws exception - c++

I've having My with an implicit ctor My(int i), I wish to cast an int into My, so I have:
#include <any>
#include <iostream>
using namespace std;
struct My {
My(int i) { cout << "int ctor\n"; }
};
ostream& operator << (ostream& os, const My& m) {
os << "My object\n";
return os;
}
int main() {
any a = 1;
auto am = My(any_cast<int>(a));
cout << a.type().name() << ": " << any_cast<int>(a) << '\n';
cout << a.type().name() << ": " << any_cast<My>(a) << '\n';
return 0;
}
Upon running, it prints:
int ctor
i: 1
i: terminate called after throwing an instance of 'std::bad_any_cast'
what(): bad any_cast
I expected that any_cast<My>(a) should be able to call My(a) to construct a new object, but actually not.
Did I mis-undertand anything?

This is simply not how std::any_cast works. It is not literally a cast between types like e.g. static_cast is.
You must provide the exact type stored in the std::any object to access its value (via std::any_cast). It is impossible to imply any conversions.
Because the type stored in the std::any is only determined at runtime, the compiler would need to emit code for every possible type that could be stored in it and be convertible to the target type, if implicit conversions were allowed. That is clearly infeasible or impossible.
There are only very few situations where std::any is the right tool for the job. In particular it will not allow you to circumvent the statically-typed nature of C++.

I expected that any_cast(a) should be able to call My(a) to construct a new object, but actually not.
No, any_cast<T>(a) succeeds if and only if T is present in a. It answers the query whether there is T in a. Not whether there is some type implicitly convertible to T. You have to do that after extracting the value yourself.

As for the manual
Throws std::bad_any_cast if the typeid of the requested T does not match that of the contents of operand.
a should contain the exact type My.
I expected that any_cast(a) should be able to call My(a) to construct a new object, but actually not.
It does not call converting constructors.

Related

Why does std::bind statically type check arguments passed to the function?

Not exactly a question but more of a musing... I wrote a program to test how 'std::bind' passes arguments to the function being binded. It seems like in this instance the C++ compiler performs static type checking:
#include <iostream>
#include <functional>
void take_int(const int *a)
{
if (a)
{
std::cout << "a is " << *a << std::endl;
}
else
{
std::cout << "null" << std::endl;
}
}
int main()
{
int *a = new(int);
*a = 4;
take_int(NULL); //prints 'null'
auto fn = std::bind(take_int, NULL); //fails to compile
fn();
return 0;
}
It seems inconsistent to be able to directly call the function with NULL but for it to fail at compile time when doing so through std::bind.
I guess std::bind is using more modern C++ features which chooses to enforce this?
This is because you are using NULL, which is deprecated. Instead, you should be using nullptr.
If you use nullptr in your snipped, code compiles as expected.
You need to keep in mind that
NULL can be an integer literal with value zero, or a prvalue of type
std::nullptr_t
In your case, it is integer literal. When you call a function with that value, it is converted to pointer - this is why calling a function directly works.
Your Compiler defines NULL as 0 which as a literal can be implicitly converted to an int*. Thats why your first call is succesful.
But std::bind() will generate an object for <void (&)(const int *),int> which can't be called since a variable of type int cannot be implicitly converted to int*.

C++ generic rvalue overload

I'm currently trying to refactor some code which uses a primitive type into something which I can tuck setters and getters into them. I wanted to make the change to the underlying code transparent, and at first I though C++'s operator overloads would help me out there.
Let's suppose I want to make an "augmented int" type, for instance, that can be treated just like a regular int, but allows for further action wherever I assign to it, and just assignment - all other properties of an int, such as adding with +=, should be preserved.
At first I first though that if I encapsulated the int inside some struct, and filled out the operator= overloads, I'd be set, like in the following example:
#include<iostream>
typedef struct PowerInt{
int x;
PowerInt(){
cout << "PowerInt created\n";
x = 0;
}
~PowerInt(){
cout << "PowerInt destroyed\n";
}
void operator=(int other){
cout << "PowerInt received " << other << "\n";
this->x = other;
}
}PowerInt;
int main(){
PowerInt a;
a = 3;
return 0;
}
The code compiles and runs as expected, but as soon as I try making anything else a regular int could do, like cout << a, or a += 2, or even a simple int b = a; assignment the compiler complains about the operators << and += missing.
Fair enough; I then though that, at least for << and "assigment =", I could get by using some sort of "generic rvalue operator", or some kind of method which returns PowerInt.x wherever my a is used as an rvalue, automatically making expressions like int c = (a + 3); and if (a == 3) {} valid.
Problem is, I can't find a way to implement this idiom, and this mostly likely has to do with either my little understanding of how operator overloading works in C++, or some language feature I'm not yet aware of. Is it possible to accomplish what I'm trying here?
If you want your PowerInt to be convertible to a normal int you can create a user-defined conversion operator:
operator int() const
{
return x;
}
Any operator that's not defined for PowerInt will then use the operator defined for a normal int.
P.S The typedef struct isn't necessary in C++.

How is the constructor used in C++? Why does it seem to allow using it as a parameter?

I stumbled upon this question (which is a different example). And most say a constructor does not return anything. However, why does my example work?
sequence(1, 2) is a constructor and obviously can be used on my machine. I use g++ and tried without option and with C++11 option. Both work in my case.
The example is from a course. I copy as is, no matter whether public makes sense or not, or something else.
Example:
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;
void printer(int i) {
cout << i << ", ";
}
struct sequence {
int val, inc;
public:
sequence(int s, int i) : val(s), inc(i) {
cout << "Sequence(" << val << ", " << inc << ")" << endl;
}
operator int() const {//LINE I
int r = val;
cout << r << endl;
return r;
}
};
int main() {
vector<int> v1(7);
fill(v1.begin(), v1.end(), sequence(1, 2)); //LINE II
for_each(v1.begin(), v1.end(), printer);
return 0;
}
Result:
Sequence(1, 2)
1
1
1
1
1
1
1
1, 1, 1, 1, 1, 1, 1,
Update
Thank you all for the answers. But I am still pretty confused, cannot get it into my head, probably missing proper terminology I think.
So far I think I understood:
sequence is a struct object
sequence(int, int) is a constructor definition and does not return anything
() operator on sequence simply returns the val value.
So why does it work:
the call to sequence(1,2) creates a temporary object that can be accessed and read
the () is used to fill the respective element. basically fill uses sequence() to get the value to fill in.
after fill has finished the temporary object is destroyed. It's scope is the scope of the function fill
Does that sound right so far?
Because you have operator int() which converts your sequence class objects to 1. You can easily observe it as it prints 1 and a newline for every conversion.
sequence(1,2) is not a constructor call, it is an explicit type conversion using functional notation, resulting in a prvalue of type sequence. This is explained in [expr.type.conv]/1 (N3337):
A simple-type-specifier (7.1.6.2) or typename-specifier (14.6) followed by a parenthesized expression-list constructs a value of the specified type given the expression list.
[...]
If the expression list specifies more than a single value, the type shall be a class with a suitably declared constructor (8.5, 12.1), and the expression T(x1, x2, ...) is equivalent in effect to the declaration T t(x1, x2, ...); for some invented temporary variable t, with the result being the value of t as a prvalue.
The reason a sequence is acceptable as an int is that it provides an implicit conversion to int operator: operator int.
Constructor does not return anything means that you can't set the return value manually. However if you use sequence(1, 2) in your code, it creates temporary object of your type.
Then the compiler tries to convert that object to int. Since you have defined the int() operator, it succeeded.
When you call sequence(1, 2) it is not the ctor who allocates memory for the temporary object, but code that the compiler generates. What the compiler generates is something like this pseudo code:
sequence *tmp = allocate_memory_from_stack_for_temp_object();
tmp->ctor(1, 2);
return *tmp;
As you can see the ctor is working on existing memory, so there is no need for the ctor function to return the constructed object. This is handled by some logic around the ctor. Of course the compiler also adds code to destroy the temporary object.
Here you are overloading the operator() "function call operator" which returns int.(converting your object to int)
constructor doesn't return anything but by use of functors(function object) you can achieve that scenario. (sry if i am wrong here, anyone let me know ur comments)
Ex : lets say I have class A.
A obj(5); // call to constructor.
int b = obj(6); // call to overloaded operator() that you need to define

Postfix increment operator

I have a custom class MyInt, encapsulating a int m_nValue data. The postfix operator
MyInt operator++(int)
{
MyInt temp(*this);
++(*this);
return temp;
}
if the operator returns an object, then why i am not able to call postfix++ operator more than once like:
MyInt value(10);
value++; // valid
value++++; // Why is this invalid?? Cant it be interpreted as (value++)++
Why does value++++ gives an error lvalue required
if i can call value.print() method defined in MyInt Class, then i should also be able to do value++++?
Wrong answer:
Because value++ is a temporary variable that holds the old value of value. You can't ++ it.
You also can't write 15++! It's similar. The former is a temporary variable, the later is a constant, none of which you can increment.
Correction: Since this answer got accepted, I am not going to change the original post, but since people will read it, I will post the correction here.
First off, I am not saying constants and temporary objects are the same concept. I was just trying to say temporary objects are not l-values, like constants are not, without actually using the word l-value.
About value++++, it is not an error. I just tested it with my g++ 4.5 and it works fine. In other answers you can read:
From section 3.10.10 of the 2003 standard:
An lvalue for an object is necessary in order to modify the object except that an rvalue of class type can also be used to modify its referent under certain circumstances. [Example: a member function called for an object (9.3) can modify the object. ]
What is inherently wrong about what you are doing is this:
Let's say value holds 10. The first value++ changes value to 11 but returns a temporary object containing 10. Then you ++ it which changes the temporary value (that you never access) to 11, but again returns a temporary object that contains 10. So value++++ behaves exactly like value++ except it does some unnecessary work.
Actually, this should work:
#include <iostream>
struct MyInt {
MyInt() : value(0) {}
MyInt& operator++() {
std::cout << "Inside MyInt::operator++()" << std::endl;
++value;
return *this;
}
MyInt operator++(int)
{
MyInt temp(*this);
++(*this);
return temp;
}
int value;
};
int main() {
MyInt mi;
std::cout << "Value before: " << mi.value << std::endl;
mi++++;
std::cout << "Value after: " << mi.value << std::endl;
}
This operator is basically just a normal member-function with fancy syntax, and as such you can invoke it on an rvalue. Note how, as Martinho explains in his comment, the effect is not the desired one, because the second increment operates on a temporary.
From section 3.10.10 of the 2003 standard:
An lvalue for an object is necessary in order to modify the object
except that an rvalue of class type can also be used to modify its
referent under certain circumstances. [Example: a member function
called for an object (9.3) can modify the object. ]

How do I typecast with type_info?

I've stored a pointer to a type_info object.
int MyVariable = 123;
const std::type_info* Datatype = &typeid(MyVariable);
How might I use this to typecast another variable to that type? I tried this, but it doesn't work:
std::cout << ((*Datatype)3.14) << std::endl;
Using the function form of typecasting doesn't work, either:
std::cout << (*Datatype(3.14)) << std::endl;
Simply you cannot do that using type_info. Also, in your example DataType is not a type, it's a pointer to an object of type type_info. You cannot use it to cast. Casting requires type, not pointer or object!
In C++0x, you can do this however,
int MyVariable = 123;
cout << (decltype(MyVariable))3.14 << endl;
cout << static_cast<decltype(MyVariable)>(3.14) << endl;
Output:
3
3
Online Demo: http://www.ideone.com/ViM2w
I don't think such casting can be done. Suppose you could do "dynamic" casting like this at runtime (not to mean dynamic_cast). Then if you used the result of the cast to call a function the compiler could no longer do type checking on the parameters and you could invoke a function call that doesn't actually exist.
Therefore it's not possible for this to work.
Typecasting isn't a run-time process, it's a compile-time process at least for the type you're casting to. I don't think it can be done.