2017-08-30 2 views
3

overload構造体と同じコードをここに書くと、http://en.cppreference.com/w/cpp/utility/variant/visitという関数が機能するように拡張されました。ここで ファンクタ基底クラスであいまいなオーバーロード

は私が
In file included from /opt/wandbox/gcc-7.2.0/include/c++/7.2.0/cassert:44:0, 
       from prog.cc:3: 
prog.cc: In function 'int main()': 
prog.cc:66:26: warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: 
    assert(overloaded(1.1) == 1.1); 
         ^
prog.cc:62:21: note: candidate 1: main()::<lambda(double)> 
     [&](double d) { return d; }, 
        ^
prog.cc:19:20: note: candidate 2: ReturnType {anonymous}::OverloadFuncImpl<ReturnType (*)(Args ...)>::operator()(Args ...) [with ReturnType = char; Args = {char}] 
     ReturnType operator()(Args... args) { 
        ^~~~~~~~ 

コンパイラとそれが必要なoperator() 1をインポートするために作るの標準的な解釈にはいくつかの問題があります

を取得エラー

#include <utility> 
#include <type_traits> 
#include <cassert> 
#include <string> 

namespace { 
    template <typename Func> 
    class OverloadFuncImpl : public Func { 
    public: 
     template <typename F> 
     explicit OverloadFuncImpl(F&& f) : Func{std::forward<F>(f)} {} 
     using Func::operator(); 
    }; 
    template <typename ReturnType, typename... Args> 
    class OverloadFuncImpl<ReturnType (*) (Args...)> { 
    public: 
     template <typename F> 
     explicit OverloadFuncImpl(F&& f) : func{std::forward<F>(f)} {} 
     ReturnType operator()(Args... args) { 
      return this->func(args...); 
     } 
    private: 
     ReturnType (*func) (Args...); 
    }; 

    template <typename... Funcs> 
    class Overload; 
    template <typename Func, typename... Funcs> 
    class Overload<Func, Funcs...> 
      : public OverloadFuncImpl<Func>, 
       public Overload<Funcs...> { 
    public: 
     template <typename F, typename... Fs> 
     explicit Overload(F&& f, Fs&&... fs) 
      : OverloadFuncImpl<Func>{std::forward<F>(f)}, 
      Overload<Funcs...>{std::forward<Fs>(fs)...} {} 
     using OverloadFuncImpl<Func>::operator(); 
     using Overload<Funcs...>::operator(); 
    }; 
    template <typename Func> 
    class Overload<Func> : public OverloadFuncImpl<Func> { 
    public: 
     template <typename F> 
     explicit Overload(F&& f) : OverloadFuncImpl<Func>{std::forward<F>(f)} {} 
     using OverloadFuncImpl<Func>::operator(); 
    }; 
} 

template <typename... Funcs> 
auto make_overload(Funcs&&... funcs) { 
    return Overload<std::decay_t<Funcs>...>{std::forward<Funcs>(funcs)...}; 
} 

char foo(char ch) { 
    return ch; 
} 

int main() { 
    auto overloaded = make_overload(
     [&](int integer) { return integer; }, 
     [&](std::string str) { return str; }, 
     [&](double d) { return d; }, 
     foo); 

    assert(overloaded("something") == "something"); 
    assert(overloaded(1.1) == 1.1); 

    return 0; 
} 

これ以下に再現コードhttps://wandbox.org/permlink/5Z2jsEjOewkGoPeXされています一つ。しかし、どういうわけかOverloadFuncImplの機能特殊化のoperator()は、usingで正しくインポートされていないようです。

上記のコードは、OverloadFuncImplを使用しない場合、またはOverloadFuncImplという機能の部分的な特殊化を除外した場合に問題ありません。

私はすでにこのコードを回避策で使用していますが、なぜ上記のコードが機能しないのか不思議です。私はそれを把握していないようだ...私はすべての基本クラスのoperator()すべてをインポートしたときにそれはなぜですか?依然としてあいまいな過負荷問題がありますか?

私は、効果的に問題に設定過負荷で関連する候補者は

呼ば
char operator()(char); 
double operator()(double) const; 

ある

+0

Btw、これはあなたの質問に直接関係しませんが、関数ポインタの実装にはさらに問題があります。右辺値参照をとる関数ポインタから過負荷を作成してみてください。 –

+0

@NirFriedmanあなたはどの部分について話していますか?コンストラクタまたは呼び出し演算子? – Curious

+0

コールオペレータ。 http://coliru.stacked-crooked.com/a/2d3469ea05c357c1 –

答えて

5
ReturnType operator()(Args... args) const { 
//          ^^^^^ 
     return this->func(args...); 
    } 

...小さい状況でエラーを再現しようとしたができませんでしたタイプがdoubleconstオブジェクトではない。

暗黙的なオブジェクトパラメータの最初の勝ち。 2番目の引数は実際の関数パラメータで勝ちます。あいまいさが続く

+0

エラーメッセージにこれが言及されなかった理由は何ですか? – Curious

+1

@Curiousそれはありますか?それはあなたに問題の候補者を教えてくれます... –

+1

@Curious私は見逃しやすい点は、ラムダの演算子()が暗黙的にconstであることです。だから、必要に応じてラムダを変更可能と宣言しなければならないのです。これは、TCの解決策をすぐに飛び出させることはありません(少なくとも、私がエラーメッセージを読んだときには私にとってではない)。 –

関連する問題