6

コンパイラが次の GetLength 関数ポインタをあいまいな
疑似コードと見なすのはなぜですか。

size_t GetLength(char*);
size_t GetLength(wchar_t*);
struct ITEM { };
double GetLength(ITEM*);

CString GetInfo(ITEM * item, std::function<double (ITEM*)> fn)
{
  ... omitted for clarity
}

ITEM * item = new ITEM;
cout << GetInfo(item, GetLength);  // <- ambiguous error

GetInfo は、二重リターン + ITEM* 引数パターンの一部のみを許可します。では、なぜ GetLength の 2 つの文字列ベースのバリエーションを考慮する (そして破棄しない) のでしょうか?

4

2 に答える 2

11

のコンストラクター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;
    }
};

これは、それ自体が呼び出し可能であるため、必要なコンテキストでコンパイルされます。(私の知る限り、完全にテストされていませんが、まだ存在しないあいまいさは導入されていません。)

于 2011-11-16T18:39:25.210 に答える
0

あなたの中括弧は一致しません。それがコンパイラがあなたを理解できない理由です

CString GetInfo(ITEM * item, std::function<double ITEM*> fn)
于 2011-11-16T18:36:11.230 に答える