5

Using C++ on Linux, I just rather stupidly wrote this:

struct in_addr ip_addr = ((struct sockaddr_in)socket_addr).sin_addr;

Instead of the intended:

struct in_addr ip_addr = ((struct sockaddr_in*)&socket_addr)->sin_addr;

Giving me this error:

"error: no matching function for call to ‘sockaddr_in::sockaddr_in(sockaddr&)"

I know why I have the error (I was trying to cast a structure), but I don't understand why the error message says what it does. Can someone please explain?

Ed King
  • 1,833
  • 1
  • 15
  • 32
  • `struct` is optional in C++. This looks like C where it is not. – nwp May 17 '17 at 10:04
  • I know `struct` is optional, but added it for clarity of the structures and marked it specifically as C++, just in case it was a C++-specific message. – Ed King May 17 '17 at 10:05
  • @nwp: It's quite amusing (sort of) how often I see `struct sockaddr_in` and similar in C++, even production C++, presumably due to copy/paste learning from C tutorials! I've even accidentally done it myself once or twice. – Lightness Races in Orbit May 17 '17 at 10:09
  • Rest-assured, `struct` doesn't exist in my actual code. But I suppose I can only appreciate the pedantry ;-) – Ed King May 17 '17 at 10:10

3 Answers3

5

When the compiler encounters a C-style cast, it tries to interpret it as one or two C++-style casts, in the following order:

  • const_cast<new_type>(expression)
  • static_cast<new_type>(expression)
  • static_cast (with extensions) followed by const_cast
  • reinterpret_cast<new_type>(expression)
  • reinterpret_cast followed by const_cast

The first choice that satisfies the requirements of the respective cast operator is selected, even if it cannot be compiled.

In your case, static_cast<sockaddr_in>(socket_addr) is selected. This is direct initialization, so the compiler looks for, and does not find, a constructor that takes a const reference to the object being cast.

Note that the same conversion does not trigger an error when applied to pointers, because language has built-in conversions between pointers of different types.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
4

When doing the cast on the type (and not the pointer), the compiler try to call the constructor of sockaddr_in that take a object of the same type as socket_addr. Since that constructor doesn't exists, the compiler throw the error you showed.

nefas
  • 1,120
  • 7
  • 16
  • 2
    Note that this is not the only possible way such a conversion could happen. `socket_addr::operator sockaddr_in`could also exist. – Angew is no longer proud of SO May 17 '17 at 09:58
  • Ah, thanks. when you say it's calling the constructor, is it the copy constructor? – Ed King May 17 '17 at 10:03
  • 1
    The copy constructor takes only one argument of the same type (but is a reference) as the class. In this case, this is a "normal" constructor that take one argument of the type of the casted value. – nefas May 17 '17 at 10:06
  • This makes sense when read in conjunction with @dasblinkenlight's answer – Ed King May 17 '17 at 10:07
2

Because that's how casts work — they convert an A to a B, and (unless B is a pointer or a reference) that requires invoking a conversion operator or a constructor. The compiler is trying to find a constructor to create a sockaddr_in from a sockaddr; none exists, hence the error.

It can't guess that you really meant to attempt a conversion to something else instead.

I've found that a large part of becoming a productive C++ programmer is learning the art of taking these compiler errors and using them to heuristically determine what the actual problem likely is. ;)

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055