14

I learned that in C++,

typedef foo* mytype;

(mytype) a        // C-style cast

and

mytype(a)         // function-style cast

do the same thing.

But I notice the function-style cast share the same syntax as a constructor. Aren't there ambiguous cases, where we don't know if it is a cast or a constructor?

char s [] = "Hello";
std::string s2 = std::string(s);     // here it's a constructor but why wouldn't it be ...
std::string s3 = (std::string) s;    // ... interpreted as a function-style cast?
Basj
  • 41,386
  • 99
  • 383
  • 673
  • 2
    Actually in the example you show *both* cases will call a `std::string` constructor. The *same* constructor even. – Some programmer dude Aug 04 '17 at 11:42
  • Note: in C++ you should in general prefer the explicit casts `static_cast`, `reinterpret_cast`, `const_cast`, `dynamic_cast`, `static_pointer_cast`, `reinterpret_pointer_cast`, `const_pointer_cast` & `dynamic_pointer_cast` (and `move` & `forward` - yes, they *are just casts*) over C-style casts. They are easier to search for in code, more explicit as to intention and safer (worst cast of C-style cast is to generate `reinterpret_cast` followed by `const_cast` for example). – Jesper Juhl Aug 04 '17 at 11:56
  • 1
    Please see this related question for the original purpose of function-style casts, and their use cases: https://stackoverflow.com/questions/4474933/what-exactly-is-or-was-the-purpose-of-c-function-style-casts – Galaxy Oct 06 '19 at 01:51

3 Answers3

15

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;
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
1

Conversion is a form of initialization. When a type is implicitly convertible to another, a functional cast is a form of direct initialization. The compiler knows which types are convertible.

Whenever something is converted to a class type, either a converting constructor of the target type or a conversion operator of the source type is used. In your examples, both casts call the default constructor.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Thanks. Ok the compiler knows, but how can I know which cases are convertible via constructor or just via changing the type without changing the value (like a c style cast)? – Basj Aug 04 '17 at 11:51
  • @Basj `how can I know which cases are convertible` you can ask the compiler using `std::is_convertible` or you can read the definition of the class (and the definition of the source object's class if appropriate) to see whether the class has an appropriate conversion constructor (or the source object has appropriate conversion operator). Conversion to a class type is always a call to a constructor. You can find out whether a type is a class by looking at its definition. – eerorika Aug 04 '17 at 11:53
  • “Whenever something is converted to a class type, a constructor is called.” — not true. A conversion operator might be called instead. And that doesn’t necessarily call a constructor either (it usually would but it might for instance return a cached object by reference). – Konrad Rudolph Aug 04 '17 at 12:15
  • @KonradRudolph interesting. I had not realized that a conversion operator may return a reference. – eerorika Aug 04 '17 at 13:46
-2

The compiler knows. And it calls the constructor when there is one in both cases.