Constructor-style casting in function call parameters
[C++11: 5.2.3/1]:
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. [..]
Examining the grammar, we see that the only way to get unsigned char
from the simple-type-specifier production is by concatenating two of them.
As evidence debunking the rumour that table 10 is stating the contrary, which I may myself have started a short while ago (:P), the table heading says "specifier(s)" (note the optional plural), and refer to the below passage:
[C++11: 5.2.3/2]:
[..] Table 10 summarizes the valid combinations of simple-type-specifiers and the types they specify. (emphasis mine)
Now, combining simple-type-specifiers is allowed in some cases:
[C++11: 7.1.6.2/3]:
When multiple simple-type-specifiers are allowed, they can be freely intermixed with other decl-specifiers in any order. [..]
… but there's no indication that this is the case with functional notation, which clearly states "a simple-type-specifier" — singular.
Therefore GCC is correct, and Visual Studio is wrong.
As for why this is the case... well, I don't know. I suspect we could come up with some ambiguous edge case, but Casey makes a good point in the comments below that allowing this would be inconsistent with function call syntax, since names of functions cannot have spaces in them.
Function style casting vs calling constructor
It's a functional-style type conversion which creates a t
from an int
by calling the constructor. There is no way to explicitly call a constructor in C++.
This is described in [expr.type.conv]
(N3337):
5.2.3 Explicit type conversion (functional notation)
1) A simple-type-specifer (7.1.6.2) or typename-specifer (14.6) followed by a parenthesized expression-list
constructs a value of the specified type given the expression list. If the expression list is a single expression,
the type conversion expression is equivalent (in definedness, and if defined in meaning) to the corresponding
cast expression (5.4). If the type specified is a class type, the class type shall be complete. 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 expressionT(x1, x2, ...)
is equivalent in effect to the declarationT t(x1, x2, ...);
for some invented temporary variablet
, with the result being the value oft
as a prvalue.
Since t
is a simple-type-specifier, this is equivalent to the corresponding cast expression. This is allowed to carry out the equivalent of a static_cast
([expr.cast]/4
), which defines the final result of the conversion:
[expr.static.cast]/4:
Otherwise, an expressione
can be explicitly converted to a typeT
using astatic_cast
of the formstatic_cast<T>(e)
if the declarationT t(e);
is well-formed, for some invented temporary variablet
(8.5). The
effect of such an explicit conversion is the same as performing the declaration and initialization and then
using the temporary variable as the result of the conversion. The expressione
is used as a glvalue if and
only if the initialization uses it as a glvalue.
Function-style cast vs. constructor
Syntactically, it is always a cast. That cast may happen to call a constructor:
char s [] = "Hello";
// Function-style cast; internally calls std::basic_string<char>::basic_string(char const*, Allocator)
std::string s2 = std::string(s);
// C-style cast; internally calls std::basic_string<char>::basic_string(char const*, Allocator)
std::string s3 = (std::string) s;
What exactly is or was the purpose of C++ function-style casts?
Function style casts bring consistency to primitive and user defined types. This is very useful when defining templates. For example, take this very silly example:
template<typename T, typename U>
T silly_cast(U const &u) {
return T(u);
}
My silly_cast
function will work for primitive types, because it's a function-style cast. It will also work for user defined types, so long as class T has a single argument constructor that takes a U or U const &.
template<typename T, typename U>
T silly_cast(U const &u) {
return T(u);
}
class Foo {};
class Bar {
public:
Bar(Foo const&) {};
};
int main() {
long lg = 1L;
Foo f;
int v = silly_cast<int>(lg);
Bar b = silly_cast<Bar>(f);
}
Function style casting using the `new T()` operator in C++
would using the new operator still count as a functional cast?
No, the use of the new
operator(like you used in your example) is not a use case of functional cast.
test t = test(1, 2);
isn't because it has more than 1 expression in parenthesis?
Both test t = test(1);
and test t = test(1,2);
are copy initializations. Now, the subexpression test(1)
is indeed a functional cast where the appropriate test
constructor will be used. While the subexpression test(1, 2)
is not as it has more than a single expression inside parenthesis.
When do casts call the constructor of the new type?
Any time a new object is created, a constructor is called. A static_cast
always results in a new, temporary object (but see comment by James McNellis) either
immediately, or through a call to a user defined conversion. (But in
order to have an object of the desired type to return, the user defined
conversion operator will have to call a constructor.)
When the target is a class type, C style casts and functional style
casts with a single argument are, by definition, the same as astatic_cast
. If the functional style cast has zero or more than one
argument, then it will call the constructor immediately; user defined
conversion operators are not considered in this case. (And one could
question the choice of calling this a "type conversion".)
For the record, a case where a user defined conversion operator might be
called:
class A
{
int m_value;
public
A( int initialValue ) : m_value( initialValue ) {}
};
class B
{
int m_value;
public:
B( int initialValue ) : m_value( initialValue ) {}
operator A() const { return A( m_value ); }
};
void f( A const& arg );
B someB;
f( static_cast<A>( arg ) );
In this particular case, the cast is unnecessary, and the conversion
will be made implicitly in its absence. But in all cases: implicit
conversion, static_cast
, C style cast ((A) someB
) or functional
style cast (A( someB )
),B::operator A()
will be called.)
C++ explicit constructor and cast
The parameter, w
, of function doSomeWork
is a Widget
that you have created as a parameter in the line
doSomeWork(Widget(15));
doSomeWork
expected a Widget
and one has been explicitly supplied using the constructor you have listed. No compiler supplied copy constructor is used because the doSomeWork(const Widget &w)
signature uses pass by reference semantics.
Just one object is constructed, although pass-by-value could have been used and clever modern compilers would defer the construction to the method's scope to avoid duplicated construction.
Constructing `long double` rvalue
Firstly, the original code is incorrect and it's a MSVC bug to silently accept it, see this question for standard references.
Since powl
is a non-overloaded function of signature:
long double powl(long double x, long double y);
you can just write powl(4, 3)
, there is implicit coversion from integer to long double.
In the more general case your options include (long double)4
, static_cast<long double>(4)
, 4.L
, and 4.0L
. The L
suffix combined with the presence of .
in the literal means a long double
literal.
This feels dirty: I'm constructing an object, not casting an int, even if the compiler will elide it.
Maybe you have a misunderstanding in this area. The code double(4)
is a cast; its official name is explicit type conversion (functional notation). Casts are prvalues, except for some cases that are not relevant here.
There is literally (ha ha) no difference whatsoever in semantics between the different syntaxes that result in prvalue of type double
and value 4
.
This is also true for class types; (std::string)x
, std::string(x)
, and static_cast<std::string>(x)
are all identical in semantics.
Related Topics
Casting to Void* and Back to Original_Data_Type*
Adding Header and .Cpp Files in a Project Built with Cmake
How to Use Pre-Compiled Headers in Vc++ Without Requiring Stdafx.H
Send Binary File Over Tcp/Ip Connection
Custom Stream to Method in C++
Building Qt 4.5 with Visual C++ 2010
Cmake: How to Change Properties on Subdirectory Project Targets
Boost Graph Copy and Removing Vertex
Off-The-Shelf C++ Hex Dump Code
How to Call a C++ Method from C
How to Append to a File with Fstream Fstream::App Flag Seems Not to Work
Reading from .Txt File into Two Dimensional Array in C++
Returning VS. Using a Reference Parameter
How to Use External Dlls in Cmake Project