代码之家  ›  专栏  ›  技术社区  ›  Ale Morales

如何使用std::shared_ptr<void>和另一种类型的std::shared_ptr进行函数重载?

  •  12
  • Ale Morales  · 技术社区  · 7 年前

    #include <functional>
    #include <memory>
    
    class C {
        public:
        void F(std::function<void(std::shared_ptr<void>)>){}
        void F(std::function<void(std::shared_ptr<int>)>){}
    };
    
    int main(){
        C c;
        c.F([](std::shared_ptr<void>) {});
    }
    

    您将看到一个编译错误:

    prog.cc:12:7: error: call to member function 'F' is ambiguous
        c.F([](std::shared_ptr<void>) {});
        ~~^
    prog.cc:6:10: note: candidate function
        void F(std::function<void(std::shared_ptr<void>)>){}
             ^
    prog.cc:7:10: note: candidate function
        void F(std::function<void(std::shared_ptr<int>)>){}
             ^
    

    有没有办法解决这一模棱两可的问题?也许是斯菲奈?

    2 回复  |  直到 7 年前
        1
  •  6
  •   max66    7 年前

    我很困惑,但我试着解释一下。

    我知道你们的lambda可以被双方接受 std::function<void(std::shared_ptr<void>)> std::function<void(std::shared_ptr<int>)> ; 您可以验证是否编译了以下两行

    std::function<void(std::shared_ptr<void>)>  f0 = [](std::shared_ptr<void>){};
    std::function<void(std::shared_ptr<int>)>   f1 = [](std::shared_ptr<void>){};
    

    int 可以转换为共享指针指向 void ; 您可以验证以下行是否已编译

    std::shared_ptr<void> sv = std::shared_ptr<int>{};
    

    在这一点上,我们可以看到

    c.F([](std::shared_ptr<void>) {});
    

    你没有通过考试 F() std::函数<作废(标准::共享\u ptr<作废>)> ; 因此,可以使用一个对象来调用 F()

    有没有办法解决这一模棱两可的问题?也许是斯菲奈?

    也许是通过标签发送。

    可以添加未使用的参数和模板

    void F (std::function<void(std::shared_ptr<void>)>, int)
     { std::cout << "void version" << std::endl; }
    
    void F (std::function<void(std::shared_ptr<int>)>, long)
     { std::cout << "int version" << std::endl; }
    
    template <typename T>
    void F (T && t)
     { F(std::forward<T>(t), 0); }
    

    这边叫

    c.F([](std::shared_ptr<void>) {});
    c.F([](std::shared_ptr<int>){});
    

    您从第一次调用中获得“void version”(均为非模板 匹配,但首选“无效版本”,因为 0 是一个 int “int版本”匹配)。

        2
  •  4
  •   Community Mohan Dere    6 年前

    为什么会这样

    这个 answer by max66

    • 您可以隐式地从 std::shared_ptr<int> std::shared_ptr<void> 而不是相反。

    • 您可以隐式地从 std::function<void(std::shared_ptr<void>)> std::function<void(std::shared_ptr<int>)> 而不是相反。

    • 可以使用参数类型从lambda隐式转换 std::函数<无效(标准::共享\u ptr<int>)> .

    • 标准::共享\u ptr<int> .

    Wikipedia this SO Q&A

    给定(伪代码)函数接口类型

    C func1(A1, A2, ..., An)
    D func2(B1, B2, ..., Bn)
    

    然后是作为 func2 func1 D 可以转换为 C Ai Bi

    要知道为什么会这样,考虑一下如果我们允许的话会发生什么 function -到- 转换为 std::function<std::shared_ptr<T>> 键入,然后尝试调用它们。

    如果我们把 std::function<void(std::shared_ptr<void>)> a; std::function<void(std::shared_ptr<int>)> b; b 其行为类似于包含 a 并向其转发电话。然后 可能会被打电话给任何人 std::shared_ptr<int> pi; . 它能把它传给 A. 标准::共享\u ptr<int> .

    如果我们把 std::function<void(std::shared_ptr<int>)> c; std::function<void(std::shared_ptr<void>)> d; 然后 d 其行为类似于包含 c D std::shared_ptr<void> pv; . 它能把它传给 C ? 不安全!没有从中转换 标准::共享\u ptr<无效> D 不知何故,我试图使用 std::static_pointer_cast 或类似的,, pv int 完全

    实际的标准规则,自C++17( [func.wrap.func.con]/7 std::function<R(ArgTypes...)> 构造函数模板

    template<class F> function(F f);
    

    评论: 此构造函数模板不得参与过载解决,除非 f 参数类型是否可以调用左值 ArgTypes... 和返回类型 R .

    其中“Lvalue callable”本质上意味着具有给定类型的完美转发参数的函数调用表达式是有效的,如果 不是 void R F 是指向成员和/或某些参数类型的指针 std::reference_wrapper<X>

    std::function ,因为它检查目标的参数类型 作用

    (在C++17之前 std::function::function(F) 模板构造函数根本没有任何SFINAE样式限制。对于像这样的重载情况以及试图检查转换是否有效的模板来说,这是个坏消息。)

    从一个指向member的指针将以这种方式解释其含义。)并给定该类 B D ,我们有一个 D* 可以隐式转换为 B* MemberType B::* 可以转换为 MemberType D::* 但反之亦然。

    怎么办

    void F(std::function<void(std::shared_ptr<void>)>);
    void F(std::function<void(std::shared_ptr<int>)>);
    
    // For a type that converts to function<void(shared_ptr<void>)>,
    // call that overload, even though it likely also converts to
    // function<void(shared_ptr<int>)>:
    template <typename T>
    std::enable_if_t<
        std::is_convertible_v<T&&, std::function<void(std::shared_ptr<void>)>> &&
        !std::is_same_v<std::decay_t<T>, std::function<void(std::shared_ptr<void>)>>>
    F(T&& func)
    {
        F(std::function<void(std::shared_ptr<void>)>(std::forward<T>(func)));
    }
    
    推荐文章