0

次のコードでは、パラメーターとして受け取るものは何でも、ファンクターを呼び出そうとしています。「何でも」は、オプションの限られたセットです (ここにある 2 つだけがコード内にあるわけではありません)。

#include <memory>
#include <iostream>

template<class T>
struct call_with_pointer {
    // last resort: T*
    template<class Callable>
    static auto call(Callable &callable, const std::shared_ptr<T> &param) -> decltype(callable(param.get())) {
        return callable(param.get());
    }
};

template<class T>
struct call_with_shared : public call_with_pointer<T> {

    // best: call with shared_ptr<T>.
    // SFINA
    // error: Candidate template ignored: substitution failure [with Callable = Test]: no matching function for call to object of type 'Test'
    template<class Callable>
    static auto call(Callable &callable, const std::shared_ptr<T> &param) -> decltype(callable(param)) {
        return callable(param);
    }

    using call_with_pointer<T>::call;
};


class Test {
public:
    bool operator () (int * x) {
        return *x == 42;
    }
};

int main ()
{
    Test t;

    auto i = std::make_shared<int>(4);

    auto x = call_with_shared<int>::call(t, i); // No matching function for call to 'call'

    return 0;
}

このコードは VS とGCCで問題なく動作します。残念ながら、clang にはありません。エラーメッセージは次のとおりです。

'call' の呼び出しに一致する関数がありません

候補テンプレートは無視されました: 置換の失敗 [Callable = Test で]: タイプ 'Test' のオブジェクトへの呼び出しに一致する関数がありません

そのため、スマート ポインターを使用する候補は無視されます。良い。しかし、うまく機能する継承された呼び出しを検討し続けることはないようです。

質問: どうすればこれを回避できますか? ここでllvmに正しいことをさせるにはどうすればよいですか?

4

2 に答える 2

2

次のことを試してください。

template<class T>
struct call_with_pointer {
    // last resort: T*
    template<class Callable>
    static auto call(Callable &callable, const std::shared_ptr<T> &param) -> decltype(callable(param.get())) {
        return callable(param.get());
    }
};

template<class T>
struct call_with_pointer_2 {
    // last resort: T*
    template<class Callable>
    static auto call(Callable &callable, const std::shared_ptr<T> &param) -> decltype(callable(param)) {
        return callable(param);
    }
};

template<class T>
struct call_with_shared : public call_with_pointer<T>, public call_with_pointer_2<T>{
    using call_with_pointer<T>::call;
    using call_with_pointer_2<T>::call;
};
于 2012-06-13T17:27:10.363 に答える
1

厳密には、C++11 の 7.3.3p15 のため、clang が正しいです (継承された関数テンプレートの using 宣言は、派生クラスのメンバー関数テンプレートと同じ名前とパラメーターを持つため無視されます)。これらの矛盾しない宣言を考慮しないという点で、その段落に欠陥があることは明らかですが。

typename YieldFirstType<std::shared_ptr<T>, Callable>::type テンプレートの 1 つで 2 番目のパラメーターの型などを使用することで回避できます。

于 2012-06-13T18:17:49.903 に答える