のコンストラクターstd::function<...>
は、関数のような入力タイプをサポートできる必要があるため、テンプレート化されています。推論しようとする単一の型はないため、オーバーロードはすべて構築可能です。型の不一致でエラーが発生したのは、後でコンパイルするまでではありません。
あなたはこれを行うことができます:
GetInfo(item, static_cast<double(*)(ITEM*)>(GetLength));
他のオーバーロードを明示的に破棄します。
つまり、これが機能しないのと同じ理由です。
void foo(int);
void foo(void*);
struct bar
{
template <typename T>
bar(T f)
{
f(5);
}
};
bar b(foo);
のコンストラクタ本体bar
は でのみ機能しますが、 がvoid foo(int)
機能する任意の関数をサポートする必要があるf(5)
ため、引数の型はテンプレート化されます。これにより、任意の関数をその場所で動作させることができます。つまり、コンパイラは、使用する最適なオーバーロードを 1 つ推測できません。
言語レベルの解決策の 1 つは、オーバーロード セットを実際にファンクター自体にすることだと思います。つまり、次のようになります。
void foo(int);
void foo(void*);
template <typename T>
double foo(int, T);
名前を付けるfoo
と (bar(foo)
または単にのようにfoo(5)
)、次のタイプのインスタンスが生成されます。
struct __foo_overload_set // internal
{
// forwarders
void operator()(int __arg0) const
{
// where __foo0 is the zeroth overload, etc...
return __foo0(__arg0);
}
void operator()(void* __arg0) const
{
return __foo1(__arg0);
}
template <typename __Arg1>
double operator()(int __arg0, __Arg1&& __arg1) const
{
return __foo2(__arg0, std::forward<__Arg1>(__arg1));
}
// converters
typedef void(*__foo0_type)(int);
operator __foo0_type() const
{
return __foo0;
}
typedef void(*__foo1_type)(void*);
operator __foo1_type() const
{
return __foo1;
}
template <typename T>
struct __foo2_type
{
typedef void(*type)(int, T);
};
template <typename T>
operator typename __foo2_type<T>::type() const
{
return __foo2;
}
};
これは、それ自体が呼び出し可能であるため、必要なコンテキストでコンパイルされます。(私の知る限り、完全にテストされていませんが、まだ存在しないあいまいさは導入されていません。)