I'm a little confused after reading something in a textbook. Regarding the code:
void doSomeWork(const Widget& w)
{
//Fun stuff.
}
doSomeWork(Widget(15));
doSomeWork() takes a const Widget& parameter. The textbook, Effective C++ III, states that this creates a temporary Widget object to pass to doSomeWork. It says that this can be replaced by:
doSomeWork(static_cast<Widget>(15));
as both versions are casts - the first is just a function-style C cast apparently. I would have thought that Widget(15) would invoke a constructor for widget taking one integer parameter though.
Would the constructor be executed in this case?
In C++ this kind of expression is a form of a cast, at least syntactically. I.e. you use a C++ functional cast syntax Widget(15) to create a temporary object of type Widget.
Even when you construct a temporary using a multi-argument constructor (as in Widget(1, 2, 3)) it is still considered a variation of functional cast notation (see 5.2.3)
In other words, your "Is this a cast or a construction" question is incorrectly stated, since it implies mutual exclusivity between casts and "constructions". They are not mutually exclusive. In fact, every type conversion (be that an explicit cast or something more implicit) is nothing else than a creation ("construction") of a new temporary object of the target type (excluding, maybe, some reference initializations).
BTW, functional cast notation is a chiefly C++ notation. C language has no functional-style casts.
Short: Yes.
Long:
You can always test those things yourself, by doing e.g.:
#include <iostream>
struct W
{
W( int i )
{
std::cout << "W(" << i << ")\n";
}
};
int main(int argc, const char *argv[])
{
W w(1);
W(2);
static_cast<W>(3);
}
which is outputting
W(1)
W(2)
W(3)
Yes, it is both :). A cast is a syntactic construct (i.e. something you type). In this case, a constructor is invoked as a consequence of the cast. Much like a constructor would be invoked as a consequence of typing
Widget w(15);
Both Widget(15) and static_cast<Widget>(15) are casts, or conversion
operators, if you prefer. Both create a new object of the designated
type, by converting 15 into a Widget. Since 15 doesn't have any
conversion operators, the only way to do this conversion is by
allocating the necessary memory (on the stack) and calling the
appropriate constructor. This is really no different that double(15)
and static_cast<double>(15), except that we usually don't think of
double as having a constructor (but the resulting double is a new
object, distinct from the 15, which has type int).
You said:
the first is just a function-style C cast apparently
The first would not compile in C, it's not C-style. C-style looks like (Widget)15. Here, the temporary object is created, using Widget::Widget(int).
Therefore, it is not a C-style cast.
Yes, of course. Any constructor takes a single parameter would be considered as CONVERSION CONSTRUCTOR. Your constructor is already taking a single int parameter, so that the compiler can "implicitly" call this constructor to match the argument (with the value 15, which is int).
There is a simple trick to prevent such errors, just use the keyword explicit before your constructor.
Check this for more information.
Yeeeah. You can replace
Widget(15)
with
static_cast<Widget>(15)
Because it will be replaced back by compiler :D
When you cast int to Widget compiler looks for Widget::Widget(int); and place it there.
Related
Think in a similar fashion like:
1. The bare name of an array is equivalent with the pointer to the first element, without the need to specify index 0.
2. toString() from Java makes it possible to use the name of an object as a string without calling any object method.
Now is there a way in C++ to use the name of a class object to refer to its first member?
Consider:
class Program
{
public:
int id;
char *str;
};
void function(int p)
{
//...
}
and then:
Program prog0;
function(prog0); // instead of function(prog0.id)
Any way to "hide" the member reference?
EDIT:
Why was the holyBlackCat's answer deleted? I was inclining to vote it as the best answer -- no offense, Mateusz. But he was the first to suggest conversion operator and the example was complete and simple.
In C++, such behaviour would be a cataclysm. If I understand correctly, Java tries to convert object of type A to object of type B by searching for first member in A, that is of type B or is implicitly convertible to B.
C++ wasn't designed that way. We like to write code, that is always predictable. You can achieve what you want, but for a price.
The best solution in this case would be conversion operator - consider:
class Program
{
public:
int id;
char *str;
operator int()
{
return this->id;
}
//You can have more than one!
operator const char*()
{
return this->str;
}
};
void function_int(int p)
{
}
void function_str(const char* s)
{
}
Now it is possible to do the following:
Program prog;
function_int(prog); //Equivalent of function_int(prog.id)
function_str(prog); //Equivalent of function_int(prog.str)
The price is, that if you add another int and place it before id it will not be used in conversion, because we stated in our operator explicitly, that "int content" of our class is represented by id and this member is considered when it comes to such conversion.
However, even this simple example shows some potential problems - overloading functions with integral and pointer types could result in very unpredictable behavior. When type contains conversion operators to both pointers and integers, it can get even worse.
Assume, that we have following function:
void func(unsigned long)
{
}
And we call func with argument of type Program. Which conversion operator would you expect to be called? Compiler knows how to convert Program to either int or const char*, but not unsigned long. This article on cppreference should help you to understand how implicit conversions work.
Also, as Barry pointed out, more meaningless constructs become available. Consider this one:
int x = prog + 2
What does it mean? It is perfectly valid code, though. That is why conversion operators should be dosed extremely carefully (in pre-C++11 era, there was a general advise, that every class should have at most one such operator).
Quote from MSDN:
If a conversion is required that causes an ambiguity, an error is generated. Ambiguities arise when more than one user-defined conversion is available or when a user-defined conversion and a built-in conversion exist.
Sometimes, simple solution to this problem is to mark conversion operator with explicit keyword, so you would need to change above calls to:
function_int((int)prog);
function_str((const char*)prog);
It is not as pretty as the previous form, but much safer. It basically means, that compiler is forbidden to perform any implicit conversion using operator marked as explicit. Very useful to avoid ambiguous calls, while still providing some flexibility in code - you can still very easily convert objects of one type to another, but you can be sure when and where these conversions are performed.
However, explicit conversion operators are still not supported by some compilers, as this is C++ 11 feature (for example, Visual C++ 11 doesn't support it).
You can read more about explicit keyword here.
Now is there a way in C++ to use the name of a class object to refer to its first member?
No, C++ doesn't have any reflection, so there's no way to actually determine what the "first member" is.
However, if what you really want is to get an ID for any object, you could just require that object to have that method:
template <typename T>
void function(const T& t) {
int id = t.getID();
// etc.
}
Without knowing more about your use-case, it's hard to know what to propose.
Take this for example:
const Integer operator+(const Integer& left, const Integer& right) {
return Integer(left.i + right.i);
}
(taken from page 496 of Thinking in C++)
What is the part after the return statement? A cast (to make the result of the sum an Integer) or a call to the constructor of the class Integer? Or maybe something else that I ignore..
This is the constructor:
Integer(long ll = 0) : i(ll) {}
Edit:
i it's long int.
Casting means "changing an entity of one data type into another". That said, you can consider Integer() as a cast from long to Integer, as the two types are related and the operation translates into "build an object of type B, starting with an object of type A".
With this syntax, there is no protection against misuse, i.e. if the constructor takes only one parameter, the parameter might not be used to build an object directly representing the first (e.g. each QWidget takes a pointer to the parent, but it is not representing its parent, obviously), and you cannot do anything to prevent this. You could block implicit initialization by marking single-parameter constructor as explicit, but nothing more.
The syntax for old-style casts and constructors with only one parameter is exactly the same, and that's the reason why a new syntax was created for the first: use new style (explicit) C++ syntax for casts, that is, const_cast, dynamic_cast, static_cast or reinterpret_cast as appropriate.
In the very words of Bjarne Stroustrup, this verbose casting syntax was introduced to make clear when a cast is taking place. Note that having four forms also allows for proper differentiation of the programmer's intent.
Finally, int() and such are considered old-style for plain types (int, long, etc.) and newvar = (T)oldvar form exists only because of C compatibility constraint.
Its a constructor call.
Object creation in c++ will be in 2 ways,
Integer* i = new Integer(args); //A Pointer i , pointing to the object created at a memory location.
or
Integer i = Integer(args); //Object i
Your case is 2nd one, but the initialized object is not assigned to i. Rather it is passed as it is.
Moreover,
A cast could be trivial if it is (DataType) value., In this case it would be surely a cast.
But in the case of DataType(value) if it is a primitive type, it would be a cast, but if it is a non-primitive type surely it will be a constructor call.
I have a following template defined so that I can perform an explicit, but safe cast:
/// cast using implicit conversions only
template <class To,class From>
inline To safe_cast( const From &from ) {return from;}
Frequently (e.g. when passing arguments into sprintf and similar functions) I would like to use this template to perform a conversion from a string class to a c-style string. However, it shows this is not possible when temporary is passed, because the temporary will not live long enough.
Consider following example:
class Object
{
public:
MyStringClass GetDebugName() const;
};
Object obj;
printf("%s",safe_cast<const char *>(obj.GetDebugName()));
The temporary from obj.GetDebugName() lives only during the safe_cast and the pointer is invalid (points to the data of the string temporary which has already been destroyed) when inside of the printf.
As a workaround I a currently using direct cast without a template call: const char *c = (const char *)(obj.GetDebugName(), but this has a drawback of reduced type safety, as the cast is unnecessarily strong (e.g. it would silently succeed even if obj.GetDebugName() would be returning int instead of a string value). static_cast might be slightly better, but even that is too strong, I would like to get an error on any situation where cast is not sure to be safe.
1) If I am not mistaken, the standard says the temporary life time is a statement (unless extended by being bound to a const reference, in which case it is the life time of the reference). When looking at the printf example above, I am not quite sure what a "statement" is, and if the behaviour I have seen is conformant or not. If the statement is the whole printf, the lifetime of the const From &from is shorter - what lifetime should I expect from the temporary? Can someone clarify?
2) Is there some other way to make a conversion which would be safe, but the result would live long enough to be useful?
Edit:
Please, consider this more a kind of general question, I am seeking for a mechanism how can a conversion like this to be done with regard to the temporary lifetime, I am not that much interested in a special case of any particular string class.
To clarify why I do not want to use .c_str or a similar member function: I would like the conversion code to be type agnostic, I do not want the code to rely on the fact I know this particular string type has c_str implemented, I want it to work even if a different string class would be returned by ObjectDebugName, or even if ObjectDebugName would be already returning const char * (which excludes the possibility of calling .operator const char *().
I can perform an explicit, but safe cast
I would call it an implicit cast done explicitly, or just and explicit implicit cast.
1) If I am not mistaken, the standard says the temporary life time is a statement (unless extended by being bound to a const reference, in which case it is the life time of the reference). When looking at the printf example above, I am not quite sure what a "statement" is, and if the behaviour I have seen is conformant or not. If the statement is the whole printf, the lifetime of the const From &from is shorter - what lifetime should I expect from the temporary? Can someone clarify?
You are correct, the temporary is destroyed after printf've returned.
The code you provided should work. If it doesn't, it means that you misprovided some important information.
I don't know why you are using your own string class here. Does the class have a member function to get the const char * out of it?
std::string GetDebugName();
printf( "%s", GetDebugName().c_str() );
would be safe as the temporary would remain valid during that statement, for example.
You can call the conversion function directly:
printf("%s", obj.GetDebugName().operator const char*());
In C++ is it possible to define conversion operators which are not class members? I know how to do that for regular operators (such as +), but not for conversion operators.
Here is my use case: I work with a C Library which hands me out a PA_Unichar *, where the library defines PA_Unichar to be a 16-bit int. It is actually a string coded in UTF-16. I want to convert it to a std::string coded in UTF-8. I have all the conversion code ready and working, and I am only missing the syntactic sugar that would allow me to write:
PA_Unichar *libOutput = theLibraryFunction();
std::string myString = libOutput;
(usually in one line without the temp variable).
Also worth noting:
I know that std::string doesn't define implicit conversion from char* and I know why. The same reason might apply here, but that's beside the point.
I do have a ustring, subclass of std::string that defines the right conversion operator from PA_Unichar*. It works but this means using ustring variables instead of std::string and that then requires conversion to std::string when I use those strings with other libraries. So that doesn't help very much.
Using an assignment operator doesn't work as those must be class members.
So is it possible to define implicit conversion operators between two types you don't control (in my case PA_Unichar* and std::string), which may or may not be class types?
If not what could be workarounds?
What's wrong with a free function?
std::string convert(PA_Unichar *libOutput);
std::string myString = convert(theLibraryFunction());
Edit answering to the comment:
As DrPizza says: Everybody else is trying to plug the holes opened up by implicit conversions through replacing them with those explicit conversion which you call "visual clutter".
As to the temporary string: Just wait for the next compiler version. It's likely to come with rvalue references and its std::string implementation will implement move semantics on top of that, which eliminates the copy. I have yet to see a cheaper way to speedup your code than than by simply upgrading to a new compiler version.
I don't think you can define "global" conversion operators. The standards say that conversion functions are special member functions. I would propse the following if I could consider the following syntax sugar:
struct mystring : public string
{
mystring(PA_Unichar * utf16_string)
{
// All string functionality is present in your mystring.
// All what you have to do is to write the conversion process.
string::operator=("Hello World!");
string::push_back('!');
// any string operation...
}
};
Be aware that polymorphic behavior of this class is broken. As long as you don't create an object of it through a pointer of type string* though, you are in the safe-side! So, this code is perfect:
mystring str(....);
As said before, the following code is broken!
string* str = new mystring(....);
....
delete str; // only deleting "string", but not "mystring" part of the object
// std::string doesn't define virtual destructor
Implicit conversions are the devil, anyway. Make it explicit with a converting function call.
No, you can't. What you could do as an alternative is to create a conversion constructor in the target class (not your case, as you want to convert to std::string - unless you derive it). But I agree to the other answers, I think an implicit conversion is not recommended in this case - especially because you're not converting from an object but from a pointer. Better to have a free function, your code will be easier to understand and the next programmer to inherit the code will for sure thank you.
Where I work, people mostly think that objects are best initialised using C++-style construction (with parentheses), whereas primitive types should be initialised with the = operator:
std::string strFoo( "Foo" );
int nBar = 5;
Nobody seems to be able to explain why they prefer things this way, though. I can see that std::string = "Foo"; would be inefficient because it would involve an extra copy, but what's wrong with just banishing the = operator altogether and using parentheses everywhere?
Is it a common convention? What's the thinking behind it?
Initializing variables with the = operator or with a constructor call are semantically the same, it's just a question of style. I prefer the = operator, since it reads more naturally.
Using the = operator usually does not generate an extra copy - it just calls the normal constructor. Note, however, that with non-primitive types, this is only for initializations that occur at the same time as the declarations. Compare:
std::string strFooA("Foo"); // Calls std::string(const char*) constructor
std::string strFoo = "Foo"; // Calls std::string(const char*) constructor
// This is a valid (and standard) compiler optimization.
std::string strFoo; // Calls std::string() default constructor
strFoo = "Foo"; // Calls std::string::operator = (const char*)
When you have non-trivial default constructors, the latter construction can be slightly more inefficient.
The C++ standard, section 8.5, paragraph 14 states:
Otherwise (i.e., for the remaining copy-initialization cases), a temporary is created. User-defined conversion sequences that can convert from the source type to the destination type or a derived class thereof are enumerated (13.3.1.4), and the best one is chosen through overload resolution (13.3). The user-defined conversion so selected is called to convert the initializer expression into a temporary, whose type is the type returned by the call of the user-defined conversion function, with the cv-qualifiers
of the destination type. If the conversion cannot be done or is ambiguous, the initialization is ill-formed. The object being initialized is then direct-initialized
from the temporary according to the rules above.87) In certain cases, an implementation is permitted to eliminate the temporary by initializing the object directly; see 12.2.
Part of section 12.2 states:
Even when the creation of the temporary object is avoided, all the semantic restrictions must be respected as if the temporary object was created. [Example:
even if the copy constructor is not called, all the semantic restrictions, such as accessibility (11), shall be satisfied. ]
I just felt the need for another silly litb post.
string str1 = "foo";
is called copy-initialization, because what the compiler does, if it doesn't elide any temporaries, is:
string str1(string("foo"));
beside checking that the conversion constructor used is implicit. In fact, all implicit conversions are defined by the standard in terms of copy initialization. It is said that an implicit conversion from type U to type T is valid, if
T t = u; // u of type U
is valid.
In constrast,
string str1("foo");
is doing exactly what is written, and is called direct initialization. It also works with explicit constructors.
By the way, you can disable eliding of temporaries by using -fno-elide-constructors:
-fno-elide-constructors
The C++ standard allows an implementation to omit creating a temporary which
is only used to initialize another object of the same type. Specifying this
option disables that optimization, and forces G++ to call the copy constructor
in all cases.
The Standard says there is practically no difference between
T a = u;
and
T a(u);
if T and the type of u are primitive types. So you may use both forms. I think that it's just the style of it that makes people use the first form rather than the second.
Some people may use the first in some situation, because they want to disambiguate the declaration:
T u(v(a));
migh look to someone as a definition of a variable u that is initialized using a temporary of a type v that gets a parameter for its constructor called a. But in fact, what the compiler does with that is this:
T u(v a);
It creates a function declaration that takes a argument of type v, and with a parameter called a. So people do
T u = v(a);
to disambiguate that, even though they could have done
T u((v(a)));
too, because there are never parentheses around function parameters, the compiler would read it as a variable definition instead of a function declaration too :)
Unless you've proven that it matters with respect to performance, I wouldn't worry about an extra copy using the assignment operator in your example (std::string foo = "Foo";). I'd be pretty surprised if that copy even exists once you look at the optimized code, I believe that will actually call the appropriate parameterized constructor.
In answer to your question, yes, I'd say that it's a pretty common convention. Classically, people have used assignment to initialize built-in types, and there isn't a compelling reason to change the tradition. Readability and habit are perfectly valid reasons for this convention given how little impact it has on the ultimate code.
You will probably find that code such as
std::string strFoo = "Foo";
will avoid doing an extra copy and compiles to the same code (a call of a single-argument constructor) as the one with parentheses.
On the other hand, there are cases where one must use parentheses, such as a constructor member initialisation list.
I think the use of = or parentheses to construct local variables is largely a matter of personal choice.
Well, who knows what they think, but I also prefer the = for primitive types, mainly because they are not objects, and because that's the "usual" way to initialize them.
But then just to confuse you even more you initialize primitives in the initialization list using object syntax.
foo::foo()
,anInt(0)
,aFloat(0.0)
{
}
It's an issue of style. Even the statement that "std::string = "Foo"; would be inefficient because it would involve an extra copy" is not correct. This "extra copy" is removed by the compiler.
I believe that is more of a habit, very few objects could be initialized using = , the string is one of them. It's also a way of doing what you said "using parenthesis everywhere (that the language allows you to use it)"
One argument that one could make for:
std::string foo("bar");
Is that it keeps things the same even if the argument count changes, i.e.:
std::string foo("bar", 5);
Doesn't work with a '=' sign.
Another thing is that for many objects a '=' feels unnatural, for example say you have a Array class where the argument gives the length:
Array arr = 5;
Doesn't feel good, since we don't construct an Array with the value 5, but with length 5:
Array arr(5);
feels more natural, since you are constructing an object with the given parameter, not just copying a value.