それがどのように機能するかについて(MSaltersが述べたように)、これは単に間違った命名に関するものです。
void*
もちろん、実際には名前が付けられます。
しかし、なぜそれint*
はconst char*
など (実際には、ユーザー定義型へのポインターを含む任意のポインター型) で機能するのでしょうか?
これは、非常に興味深い C++ 例外処理の問題に関連していると推測できます。catch(void*)
例外ハンドラーは、(cv 互換の) ポインター型の例外を実際にキャッチします。
例:
try
{
throw "Catch me if you can!";
}
catch(void* e)
{
// ...and I can!
std::cout << "Gotcha!" << std::endl;
}
ここでは、スローchar*
(Visual C++ では char リテラルはchar*
ではなくconst char*
) をスローし、 でキャッチしvoid*
ます。そしてそれはうまくいくでしょう!
答えは C++ Holy Standard にあります:
§15.3 例外の処理
15.3.3 次の場合、ハンドラーはタイプ E の例外オブジェクトに一致します。
...
ハンドラーの型は cv1 T* cv2 であり、E はポインター型であり、次のいずれかまたは両方によってハンドラーの型に変換できます — 標準のポインター変換 (4.10) で、プライベート クラス、プロテクト クラス、またはあいまいなクラスへのポインターへの変換は含まれません。
...
そして4.10は、標準のポインタ変換には次への変換が含まれると言っていますvoid*
:
4.10.2 「cv T へのポインター」型 (T はオブジェクト型) の prvalue は、「cv void へのポインター」型の prvalue に変換できます。
また、Visual Studio デバッガーも同様に機能しますが、正確にはこの方法ではないことに注意してください。違いは、cv 修飾子を無視することです。したがってvoid
、例外ダイアログでは、実際には any を意味します[any cv] void*
。Catch ハンドラはそれらを無視しません:
try
{
struct Throwee {};
const Throwee* t = nullptr;
throw t;
}
catch(void* e)
{
// Will be missed
std::cout << "Gotcha!" << std::endl;
}
catch(const void* e)
{
// Will be catched
std::cout << "Gotcha const!" << std::endl;
}