teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

5

fix typo

2019/01/15 08:39

投稿

yohhoy
yohhoy

スコア6191

answer CHANGED
@@ -47,7 +47,7 @@
47
47
 
48
48
 
49
49
  ----
50
- おまけ: 実は質問のケースでは、下記コードのようにプロトタイプ宣言型と実引数の型を厳密位置させると、期待通りWinSockの `bind` が呼び出されるようになります。しかし、この解決方法はあまりにC++言語の難解なルールに依存しているため、素直に名前空間を分けて扱うことをおススメします。
50
+ おまけ: 実は質問のケースでは、下記コードのようにプロトタイプ宣言型と実引数の型を厳密一致させると、期待通りWinSockの `bind` が呼び出されるようになります。しかし、この解決方法はあまりにC++言語の難解なルールに依存しているため、素直に名前空間を分けて扱うことをおススメします。
51
51
 
52
52
  ```cpp
53
53
  // OK: 明示的なキャストにより全ての引数型を厳密一致させる

4

update

2019/01/15 08:39

投稿

yohhoy
yohhoy

スコア6191

answer CHANGED
File without changes

3

update

2019/01/15 08:09

投稿

yohhoy
yohhoy

スコア6191

answer CHANGED
@@ -54,4 +54,5 @@
54
54
  status = bind((SOCKET) recvSocket,
55
55
  (const struct sockaddr *) &recvSockAddr,
56
56
  (int) sizeof(recvSockAddr));
57
- ```
57
+ ```
58
+ Demo: [https://www.godbolt.ms/z/NiUAlN](https://www.godbolt.ms/z/NiUAlN)

2

refinement

2019/01/15 08:09

投稿

yohhoy
yohhoy

スコア6191

answer CHANGED
@@ -39,11 +39,11 @@
39
39
 
40
40
  つまり、この関数呼出しには `int` → `unsigned __int64` 型変換(整数拡張)と、`struct sockaddr *` → `const struct sockaddr *` 型変換(const付与)が必要となります。通常であればこれらの型変換は暗黙に行われるため、プログラマが意識する必要はありません。WinSockはC言語時代に設計された古風なAPI仕様ですから、このコードのような型キャストは自然に行われるものと思います。
41
41
 
42
- 一方、C++標準ライブラリ `std::bind` 関数テンプレートでは実引数から全てのパラメータ型を推論するため、第1引数型`F`==`int`, 第2引数型以降`BoundArgs...`=={`struct sockaddr *`, `int`}と推論されます[※]。つまり、全ての実引数に関数パラメータが完全一致する関数が(意図せず)生み出されます。
42
+ 一方、C++標準ライブラリ `std::bind` 関数テンプレートでは実引数から全てのパラメータ型を推論するため、第1引数型`F`==`int`, 第2引数型以降`BoundArgs`=={`struct sockaddr *`, `int`}と推論されます[※]。つまり、全ての実引数に関数パラメータが完全一致する関数が(意図せず)生み出されます。
43
43
 
44
44
  ソースコード中で `using namesapce std;` を行った場合、この `std::bind` 関数テンプレートが、元々グローバル名前空間にあるWinSockの `bind` 関数と同列に並びます。C++言語の関数オーバーロード解決規則は非常に複雑ですが、ここでは「型変換が必要となる候補:WinSock `bind`関数」と「型変換が不要な候補:C++標準ライブラリ`std::bind` 型推論結果」が天秤にかけられた結果、プログラマの意図しない後者が選択されています。
45
45
 
46
- ※注:厳密にはForwarding Referenceとなっているため、テンプレートパラメータ`F`==`int&`に型推論されます。
46
+ ※注:厳密にはForwarding Referenceため、テンプレートパラメータ`F`==`int&`、第1引数型は`int&`に型推論されます。また可変テンプレートパラメータ`BoundArgs`=={`struct sockaddr *`, `int`}となり、第2,3引数型はそれぞれ`struct sockaddr *&&`, `int&&`に型推論されます。
47
47
 
48
48
 
49
49
  ----

1

refinement

2019/01/15 08:07

投稿

yohhoy
yohhoy

スコア6191

answer CHANGED
@@ -20,7 +20,7 @@
20
20
  ResultType bind(F&& f, BoundArgs&&... bound_args);
21
21
  ```
22
22
 
23
- 説明のため、`bind` 関数呼出し元コードのエッセンスだけ抽出します。ここでは、実引数に指定する第1引数型(`int`)および第2引数型(struct sockaddr *)が、WinSock `bind` 関数プロトタイプ宣言の第1引数型(`SOCKET`==`unsigned __int64`)および第2引数型(`const struct sockaddr *`)とは **厳密一致していない** ことに着目してください。
23
+ 説明のため、`bind` 関数呼出し元コードのエッセンスだけ抽出します。ここでは、実引数に指定する第1引数型(`int`)および第2引数型(`struct sockaddr *`)が、WinSock `bind` 関数プロトタイプ宣言の第1引数型(`SOCKET`==`unsigned __int64`)および第2引数型(`const struct sockaddr *`)とは **厳密一致していない** ことに着目してください。
24
24
  ```cpp
25
25
  // Windows/WinSock標準ヘッダによる型名定義
26
26
  typedef unsigned __int64 UINT_PTR;
@@ -43,13 +43,15 @@
43
43
 
44
44
  ソースコード中で `using namesapce std;` を行った場合、この `std::bind` 関数テンプレートが、元々グローバル名前空間にあるWinSockの `bind` 関数と同列に並びます。C++言語の関数オーバーロード解決規則は非常に複雑ですが、ここでは「型変換が必要となる候補:WinSock `bind`関数」と「型変換が不要な候補:C++標準ライブラリ`std::bind` 型推論結果」が天秤にかけられた結果、プログラマの意図しない後者が選択されています。
45
45
 
46
- ※注:厳密にはForwaring Referenceとなっているため、テンプレートパラメータ`F`==`int&`に型推論されます。
46
+ ※注:厳密にはForwarding Referenceとなっているため、テンプレートパラメータ`F`==`int&`に型推論されます。
47
47
 
48
48
 
49
49
  ----
50
50
  おまけ: 実は質問のケースでは、下記コードのようにプロトタイプ宣言型と実引数の型を厳密位置させると、期待通りWinSockの `bind` が呼び出されるようになります。しかし、この解決方法はあまりにC++言語の難解なルールに依存しているため、素直に名前空間を分けて扱うことをおススメします。
51
51
 
52
52
  ```cpp
53
- // OK: キャストにより全ての引数型を厳密一致させる
53
+ // OK: 明示的なキャストにより全ての引数型を厳密一致させる
54
+ status = bind((SOCKET) recvSocket,
54
- status = bind((SOCKET)recvSocket, (const struct sockaddr *)&recvSockAddr, (int)sizeof(recvSockAddr));
55
+ (const struct sockaddr *) &recvSockAddr,
56
+ (int) sizeof(recvSockAddr));
55
57
  ```