I'm working on a legacy library that needs to be backwards compatible with C++03, but is also forward compatible to take advantage of C++11 features like move semantics and explicit casting.
So, is it possible to emulate explicit casting in C++03? I know obviously about the explicit bool (or "safe" bool) idiom - but that's only for casting to a boolean type. Is it possible to emulate a general explicit cast operator in C++03?
I checked around, and found a discussion about this in a book called "Imperfect C++ : Practical Solutions for Real-Life Programming".
In this book, they discuss some ideas about emulating an explicit cast in C++03 (the book was written before C++11). Ultimately, they recommend creating an explicit_cast<T> template. However, I don't like that solution because I want users to simply be able to use static_cast<T>, which works fine in C++11.
So, another solution was to force the compiler to do two conversions, which will disallow implicit conversions. An example of that would be something like:
class int_cast
{
public:
int_cast(const int& v) : m_value(v)
{ }
operator int() const
{
return m_value;
}
private:
int m_value;
};
struct Foo
{
Foo()
{
x = 10;
}
operator int_cast() const
{
return int_cast(x);
}
int x;
};
Here, a Foo should be explicitly convertible to int, but not implicitly. (This code is lifted almost verbatim from Imperfect C++, except in their example they are converting a custom Time object to a std::tm.
However, this doesn't actually work, at least not using GCC 4.7.2:
Foo f;
int x = static_cast<int>(f);
This results in :
test3.cpp: In function ‘int main()’:
test3.cpp:44:28: error: invalid static_cast from type ‘Foo’ to type ‘int’
So I guess "Imperfect C++" is wrong here. The compiler wasn't able to convert a Foo to an int, even with an explicit cast. (Maybe this worked on older compilers?) So, is there anyway to emulate this in C++03 (without using a custom cast operator)?
"Imperfect C++" is right, because it uses a custom "keyword" - actually a function name masquerading as a keyword (not unlike eg.: Tribool's indeterminate). If you try to static_cast you crash against the limitation that the language can only accept conversion chains that involve up to one user-defined type, whereas you have two conversions - from "Foo" to "int_cast" and from there to int.
If you want specifically to be able to static_cast then you'll probably have to hack something with macros to supersede normal static_cast... and accept to live in Undefined Behaviour Land. My preferred choice is to actually work in the inverse direction: simply use explicit_cast and use a macro to redefine it as a static_cast invocation when in C++11 mode. I use explicit cast in my C++ backports toolkit and thus in all the C++ code I write, and I have found no important issues so far.
Related
Considering the following function template func declared within MyClass class template:
template < T >
class MyClass {
public:
MyClass() = default;
// ...
template < typename oT >
oT func() {
return static_cast< oT >(_m); // alternative, return oT(_m);
}
// ...
protected:
T _m;
};
Is there any advantage in calling static_cast< oT >(_m) over explicit instantiation i.e. oT(_m)?
oT(_m) will allow many more conversions than is probably intended. If static_cast<oT>(_m) wouldn't be possible, then oT(_m) will also try a const_cast, static_cast followed by const_cast, reinterpret_cast and reinterpret_cast followed by const_cast.
For example if T is const int* and oT is double*, then oT(_m) will succeed, while static_cast<oT>(_m) will fail. But using the result from oT(_m) as if it was a pointer to a double will result in undefined behavior.
If T and oT are pointers to classes that is maybe even more dangerous, since oT(_m) will always compile, whether or not there is an inheritance relation between the two classes.
Even static_cast allows for some conversions that may not be intended. For example it can downcast pointers to classes.
Another alternative is simply return _m;. This is weaker than both variants above. It will only allow for copy-initialization. However that might be too weak depending on your use case. For example it will not use explicit constructors and conversion functions. On the other hand before C++17 it doesn't require oT to be move-constructible, which the first two variants do require before C++17.
So you will need to decide what casts are supposed to be allowed and which ones are supposed to fail.
However, nothing prevents a user from calling func<T>() to obtain the original type anyway and the user can then simply cast it however they like, so I am not sure what is gained here over a simple getter.
Even more so, the user can in either case call func<T&>() and will get a reference to the member, thereby making the protected somewhat pointless. Maybe the allowed types T need to be constrained via SFINAE/requires-clause.
Why is the following allowed to be compiled in C++?
#include<iostream>
using namespace std;
class mytest
{
public:
operator int()
{
return 10;
}
operator const int()
{
return 5;
}
};
int main()
{
mytest mt;
//int x = mt; //ERROR ambigious
//const int x = mt; //ERROR ambigious
}
Why does it make sense to allow different versions (based on constness) of the conversion operator to be compiled when their use always results in ambiguity?
Can someone clarify what I am missing here?
For conversion they're ambiguous; but you might call them explicitly. e.g.
int x = mt.operator int();
const int x = mt.operator const int();
I believe that in the strictest sense, even if it doesn't really make much sense for const, this is legitimate.
There is a difference between a function declaration and a function type, and they do not have the same constraints.
Function declarations may not differ in only their return type or (since C++17) exception specification. However, no such thing is said about the function type (to my knowledge).
The standard [class.conv.fct] decribes conversion functions as having such-and-such form (three alternatives listed), all of which do not look like normal function declarations, in particular they very obviously have no return type.
It does state, that the function type is "function taking no parameter returning conversion-type-id", but nowhere is it mentioned that conversion function declarations have any such thing as a return type. On the contrary, the three alternative forms listed very clearly do not have a return type.
Since conversion functions don't have a return type (... in their declaration), it cannot conflict. So, I guess, in the strictest, most pedantic sense, it's even kinda "legal", whether it makes sense or not.
If you think about it, then it somehow has to be legal, too. A class may very well have more than one conversion function to different things (not just differing by const). Such code does exist, and it sometimes makes a lot of sense going that way.
You might for example have a class File that converts to either a string (the filename) or to a handle_t (the operating system handle) in case you want to use some OS-specific or exotic function that your wrapper class doesn't directly support (think writev, tee, or epoll?) It's certainly something you'd expect to work!
If, however, we treated conversion functions as "just functions", then they'd only differ in their return type, which would render the declarations illegal. So... that wouldn't work.
why does it make sense to allow different version(based on constness) of conversion operator (to be compiled) when their use always result in ambiguity;
It usually makes no sense (apart from highly artificial use cases) and a compiler could warn you about it:
prog.cc:12:25: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]
operator const int()
^
I come to the conclusion, that it's not explicitly allowed to write conversation operators that only differ by constness of their return value. It is too expensive for the compilation process to explicitly disallow it.
Remember that (member) functions that only differ by their return type
class mytest
{
int f();
const int f();
};
are forbidden:
error: ‘const int mytest::f()’ cannot be overloaded
It's just that conversion operators start with operator that makes the difference.
Consider:
template<typename T>
struct Prop
{
T value;
operator T() { return value; }
};
int main()
{
Prop<float> p1 { 5 };
Prop<std::vector<float>> p2 { { 1, 2, 3 } };
float f1 = p1; // Works fine
float f2_1_1 = p2.value[0]; // Works fine
float f2_1_2 = p2[0]; // Doesn't compile
return 0;
}
Why doesn't the line marked as such compile? Shouldn't it perform implicit conversion using the supplied conversion operator into std::vector<>, so that the [] can be found?
There are (many) other questions on this site that ask variations on this question, but I couldn't find one that I think applies here. Does it have to do with std::vector being a template?
Implicit conversions are not considered for objects of member function calls, including the subscript operator overload.
Consider the consequences if that were allowed: Every single time any undeclared member function is called like this, the compiler would have to figure out all the types that the object can be converted to (note that any other otherwise unrelated type could have a converting constructor), and check if that has declared the missing member function. Not to mention how confusing that would be for the reader of the code (the conversion might be obvious in your conversion operator case, but not in the converting constructor case, and as far as I know, they are not otherwise treated differently).
So is there a notationally convenient way to get Prop to behave the way I want
You would have to define a member function for each of the member function of vector that you want to pass pass through transparently. Here is the subscript operator as an example:
auto operator[](std::size_t pos) {
return value[pos];
}
auto operator[](std::size_t pos) const {
return value[pos];
}
The problem is of course that all wrapped member functions must be explicitly declared. Another problem is arguments whose type depend on T. For example, vector::operator[] uses vector::size_type, which might not be defined for all T that you might use (certainly not for float). Here we make a compromise and use std::size_t.
A less laborious way of creating such "transparent" wrapper is inheritance. A publicly inheriting template would automatically have all the member functions of the parent and be implicitly convertible to it and can be referred by pointers and references of parent type. However, the transparency of such approach is a bit problematic mainly because ~vector is not virtual.
Private inheritance allows same wrapping as your member approach, but with much nicer syntax:
template<typename T>
struct Prop : private T
{
using T::operator[];
using T::T;
};
Note that inheritance approach prevents you from using fundamental types as T. Also, it makes the implicit conversion impossible (even with conversion operator) , so you cannot use Prop as T in free functions that expect T.
PS. Note that your conversion operator returns a value, so the vector must be copied, which may be undesirable. Consider providing reference versions instead:
operator T&&()&& { return *this; }
operator T&()& { return *this; }
operator const T&() const& { return *this; }
the same way that any of the
p2.size();
p2.begin();
p2.push_back(24);
// etc.
don't make sense to compile
also
p2[0];
which is equivalent with
p2.operator[](0);
doesn't make sense to compile\
If you want this behavior (i.e. for Prop<T> to borrow T members) there is a C++ proposal by Bjarne to add the dot operator to the language. I would work the same way that operator -> works for smart pointers. AFAIR it had a lot of controversy and so I wouldn't hold my breath for it.
A bit of background for the operator dot proposal—Bjarne Stroustrup
Operator Dot (R3) - Bjarne Stroustrup, Gabriel Dos Rei
Smart References through Delegation: An Alternative to N4477's Operator Dot - Hubert Tong, Faisal Vali
Alternatives to operator dot - Bjarne Stroustrup
Why can one cast a std::ostream to a void pointer? I am not aware of any such conversion operator in std::ostream. Code below
#include <iostream>
int main()
{
void *p = std::cout; // why does this work?
}
I'm asking this question since I've seen a placement operator new invoked as
Foo* pFoo = new (std::cerr) Foo;
and have absolutely no idea why would one write such a thing.
PS: I am compiling with g++ 4.9.2 with or without -std=c++11. clang++ does not accept the code.
PSS: Found out that due to the so called "safe bool problem" (see #nicebyte's answer), in pre C++11 a void* conversion operator was defined for std::ostream, which was then removed in C++11. However, my code compiles fine in C++11 using g++. More than that, clang++ rejects it no matter what version of the standard I use, even with -std=c++98, although my understanding is that it should accept if compiled as pre-C++11.
Read this (your question is answered in the very last section, "The safe bool problem").
To elaborate a bit, the implementation defines an implicit conversion to void* defined for things like std::cin and std::cout, just so that code like while(std::cin>>x){...} compiles, while code like int x = std::cin; doesn't. It's still problematic because you can write stuff like in your example.
C++11 solves this problem by introducing explicit conversions.
An explicit conversion operator looks like this:
struct A {
explicit operator B() { ... } // explicit conversion to B
};
When A has an explicit conversion to B, code like this becomes legal:
A a;
B b(a);
However, code like this is not:
A a;
B b = a;
A construct like if(std::cin) requires cin to be converted to bool, the standard states that in order for the conversion to be valid in that particular case, code like bool x(std::cin); should be "legal". Which can be achieved by adding an explicit conversion to bool. It allows cin/cout to be used in the above context, while avoiding things like int x = std::cout;.
For more information, refer to Bjarne's page as well as this question.
Answering only the follow-up, since nicebyte's answer is perfect for the original question.
Chances are, your gcc is set up to use libstdc++ (which hasn't changed the operator yet due it being an ABI-breaking change), and your clang is set up to use libc++ (which was from the beginning intended as a C++11 standard library and isn't quite conformant in C++98 mode - it provides a bool conversion operator that is explicit in C++11).
I think it's to allow for if (std::cout) ... without allowing for implicit conversion to bool, or something like that.
I came from Java, so when need to call a function like this:
struct A {
int a;
A(int a) : a(a){ }
};
A foo(A a){
return A(a);
}
I tend to write something like
A a = foo(A(10));
and it works perfectly fine. But I learnt that it can also be done in this way::
A a = foo(static_cast<A>(10));
I.e. it enforces the implicit conversion. So, as a rule of thumb should we alsways use static_cast-style when we need to exploit implicit conversion? Or there are some cases where function/C-style casts may be necessary?
You never need C-style casts in C++. As for your examples, the most common way to write it would be this one:
A a = foo(A(10));
There are two separate aspects worth (re)consideration here: should A::A(int) be left implicit, and how best to construct an A to pass to foo.
For the former, there's no way of deciding without knowing the usage A should support, but it's generally recommended to err on the side of having explicit constructors if unsure.
For construction, use A(10) (with C++11, A{10} works too), or just 10 to rely on the implicit conversion. Note that A(10) is a constructor call not a cast: there's no need to consider static_cast<>() as a preferred casting notation. The old C-style cast notation is actually (T)
cast-expression, per 5.4 [expr.cast] in the C++ Standard.
When you want to do a conversion from type A to B, you have two syntaxes to define the conversion:
class B
{
public:
B(A); # Conversion constructor.
};
or
class A
{
public:
operator B(); # Conversion operator.
};
For a case like:
void f(B b);
int main()
{
A a;
f(a);
}
If the first version exists, it creates a temporary object of class B, using a as parameter. If the second version exists (and you implement it, of course), it calls the operator B() of class A to create an object of type B from a. If both exists, the compiler throws you a message of ambiguity error.
About down/up-casting, implicit conversions allow upcasting (if source and target types are references/pointers), even if the target base is an innacesible (private) base class of the source. Implicit conversions also allow conversion from a non-const source type to a const target type, or also conversion from rvalue to lvalue and so on.
These are, in short, the rules of implicit conversions. A more complete guide (considering built-in versus user-defined types and built-in conversions) is here.
If you use the C++-casting:
f(static_cast<B>(a));
its nearly the same but with some differences: if B is an innaccesible (private) base of a, the cast isn't allowed. The other difference is that downcasting is allowed without runtime check (if B is a derived class of A it allows the casting, even if a isn't actually an object of type B). That is allowed because runtime check is slow, so, if you KNOW a is actually of type B, you can safely apply the casting without runtime check.
Other castings are:
const_cast<B>(a)
Only to change from const to non-const and viceversa.
reinterpret_cast<B>(a);
Cast everything. Nearly no rules involved. If a conversion from a to B doesn't exists, it just takes the memory region of a and returns it as an object of type B. Its the fastest cast alive.
dynamic_cast<B>(a);
Downcasting with runtime check (both types must be references or pointers). If the real type of a isn't B (not even a base class of the real type of a), an exception or null pointer is thrown/returned (according to if a or B are references or pointers).
Lastly, the C-casting:
f((B)a);
What the C-casting does is to try different castings (except dynamic_cast, and also allowing casting to innacesible base classes) and use the first which works. I would say the C-casting is as powerful as the implicit cast.
The explicit casting with syntax of funcion call:
f(B(a));
is equivalent to the C-casting in behaviour.