ぷるぷるの雑記

低レイヤーがんばるぞいなブログ. 記事のご利用は自己責任で.

C++でbind()が使えない

以下のコードはVisual StudioでWinsock2を使おうとしたときのものです. Microsoftのサンプルコードをコピペしただけなのでビルドできると思いきやコンパイルエラーになります.

#include <iostream>
#include<WinSock2.h>
#include<ws2tcpip.h>
#include<functional>

/* これがないとリンク時にエラーになる */
#pragma comment( lib, "ws2_32.lib" )

using namespace std;

int main()
{
    WSADATA wsaData;
    struct addrinfo *result;

    struct addrinfo hints;
    hints.ai_family   = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags    = AI_PASSIVE;

    // Resolve the local address and port to be used by the server
    int iResult = getaddrinfo(NULL, "12345", &hints, &result);
    if (iResult != 0) {
        printf("getaddrinfo failed: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    SOCKET ListenSocket;

    ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
    
    if (ListenSocket == INVALID_SOCKET) {
        printf("Error at socket(): %ld\n", WSAGetLastError());
        freeaddrinfo(result);
        WSACleanup();
        return 1;
    }

    iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);

        ....

}

エラー内容は以下になります.

「'=': 'std::Binder<std::Unforced,SOCKET &,sockaddr *&,int>' から 'int' に変換できません。」

エラーの原因

このエラーは WinAPIのbind()と、std::bind()が衝突しているのが原因です . つまり、functionalがインクルードされ、using namespace stdしているのが原因です. 解決策としては以下の2つが考えられます.

グローバルスコープを指定してbind()を利用する

Winsock2のbind()はグローバルスコープに定義されているので、スコープ解決演算子::を利用して明示的にグローバルスコープのbind()を呼び出せばコンパイルエラーは出なくなります.

/* グローバルスコープのbind()を明示的にコール */
iResult = ::bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);

using namespace stdをしない

std名前空間を使わなければbind()はグローバルスコープのbind()と認識されます. functionalの方のbindが使いたくなったらstd::bind()と呼び出せばよいです.

まとめ

WinAPIやWinsockなどの関数はグローバルスコープで定義されている. 名前が衝突したときは明示的にグローバルスコープを指定するか名前空間のusing namespaceを避ければよい.

参考

learn.microsoft.com