C++ 动态转换为函数参数类型(C+;+;)

C++ 动态转换为函数参数类型(C+;+;),c++,c++11,templates,casting,dynamic-cast,C++,C++11,Templates,Casting,Dynamic Cast,在f1()中,我希望能够动态地将其foo参数转换为与f2()的参数相同的类型(Bar,Qux等)。这可能吗 structfoo{ virtual~Foo()=默认值; }; 结构栏:公共Foo{}; 结构Qux:publicfoo{}; 模板 无效f1(T f2、Foo和Foo){ //将foo动态强制转换为f2参数的类型? f2(动态_-cast(foo)); } int main(){ 酒吧; Qux-Qux; f1([](巴&巴){},巴); f1([](Qux&Qux){},Qux);/

f1()
中,我希望能够动态地将其
foo
参数转换为与
f2()
的参数相同的类型(
Bar
Qux
等)。这可能吗

structfoo{
virtual~Foo()=默认值;
};
结构栏:公共Foo{};
结构Qux:publicfoo{};
模板
无效f1(T f2、Foo和Foo){
//将foo动态强制转换为f2参数的类型?
f2(动态_-cast(foo));
}
int main(){
酒吧;
Qux-Qux;
f1([](巴&巴){},巴);
f1([](Qux&Qux){},Qux);//此处出错!
}

您可以编写一个函数模板来推断函数指针的参数类型:

template<typename Ret, typename Arg>
Arg arg(Ret(*)(Arg));

请注意,
+
将其作为参数传递给
arg
时,会将lambda衰减为函数指针。只有当lambda
f2
只有一个参数,并且没有任何捕获时,这才起作用。

我努力使用有状态lambda的推导成员函数指针来实现这一点,但最终成功地使用了SFINAE,它更详细,但可以使用有状态lambda

template<class T>
auto f1(T f2, Foo &foo) -> decltype(f2(dynamic_cast<Bar&>(foo))) {
    return f2(dynamic_cast<Bar&>(foo));
}
template<class T>
auto f1(T f2, Foo &foo) -> decltype(f2(dynamic_cast<Qux&>(foo))) {
    return f2(dynamic_cast<Qux&>(foo));
}
模板
自动f1(T f2,Foo&Foo)->decltype(f2(动态转换(Foo))){
返回f2(动态_转换(foo));
}
模板
自动f1(T f2,Foo&Foo)->decltype(f2(动态转换(Foo))){
返回f2(动态_转换(foo));
}

这是模板转换
运算符的作业

template <typename T>
struct dynamic_caster
{
    T *ptr;
    dynamic_caster(T &ref) : ptr(&ref) {}
    template <typename U>
    operator U &() const
    {
        return *dynamic_cast<std::remove_reference_t<U> *>(ptr);
    }
};

template<class T>
void f1(T f2, Foo &foo)
{
    f2(dynamic_caster{foo});
}
模板
结构式动态连铸机
{
T*ptr;
动态_-caster(T&ref):ptr(&ref){}
模板
运算符U&()常量
{
返回*动态_转换(ptr);
}
};
模板
无效f1(T f2、Foo和Foo)
{
f2(动态_-caster{foo});
}

你不能这样做,至少不能直接这样做。 问题在于,无约束类型
T
(函数对象的类型)可能会对
operator()
有多个重载。 它甚至可能是一个模板化的操作符。 这也适用于lambda(甚至可能是
auto
lambda)

换句话说,即使有办法,现在C++中没有足够的内省来做这件事。 在我看来,即使你可以,这也可能表明设计中存在缺陷。 (@MooingDuck的答案设计似乎更有希望。)

所以你必须稍微改变你正在做的事情。 例如,您的lambda似乎是无状态的,这意味着您可以:

  • 使用自由函数
  • 将(无状态)lambda衰减为函数指针(提示,使用
    +
    操作衰减lambda(ab))
  • 一旦你接受了这一点,从那开始就很容易了; 您可以使用来推断函数的(现在是唯一的)定义参数

    #include <boost/type_traits.hpp>
    
    struct Foo {
      virtual ~Foo() = default;
    };
    struct Bar : public Foo {};
    struct Qux : public Foo {};
    
    template<class T>
    void f1(T f2, Foo &foo) {
      // dynamically cast foo to type of f2's argument
      f2(dynamic_cast<typename boost::function_traits<decltype(*f2)>::arg1_type&>(foo));
    }
    
    int main() {
      Bar bar;
      Qux qux;
      f1(+[](Bar &bar) {}, bar);
      f1(+[](Qux &qux) {}, qux); // works now!
    }
    
    #包括
    结构Foo{
    virtual~Foo()=默认值;
    };
    结构栏:公共Foo{};
    结构Qux:publicfoo{};
    模板
    无效f1(T f2、Foo和Foo){
    //将foo动态强制转换为f2参数的类型
    f2(动态_-cast(foo));
    }
    int main(){
    酒吧;
    Qux-Qux;
    f1(+[](巴&巴){},巴);
    f1(+[](Qux&Qux){},Qux);//现在可以工作了!
    }
    


    如果您想要一个更通用的解决方案,您必须定义一个带有内部或sfinae检测到的“第一个参数”的函数对象协议。e、 g.
    struct F{using arg1_type=…;auto operator()(arg1_type)const{…} > 

    我尝试了类似的方法,但是“错误:ISO C++禁止使用绑定成员函数的地址来形成指向成员函数的指针”:(.哦,你正在将lambda转换为函数指针,这只适用于无状态lambda。真的很难用有状态lambda实现它:可能最好将成员更改为引用并重命名为
    dynamic\u explorer
    ,但是头部爆炸做得很好!如果我以
    f2
    的形式传递一个函子,这也会起作用吗?@Jack Y你已经传递了一个函子。它只有在函子的
    操作符()
    不是模板并且可能也没有重载时才起作用。谢谢@HolyBlackCat。即使在
    操作符()的情况下,我也无法让它实际用于函数对象
    没有过载。不过没什么大不了的!再次感谢您的帮助。是的,如果运算符()过载,则所有赌注都无效(限制与我的答案相同)@MooingDuck的答案似乎是最优雅的,只是需要编写几个逐案的函数。谁知道呢,模板和继承不能很好地结合在一起。这实际上表明OP并不需要推断参数的类型,它需要知道某个参数是否有效,这是一个更简单的任务是今年到目前为止我最喜欢的问题之一。表面上看起来很简单,但……不——看看所有漂亮的答案。+1。
    #include <boost/type_traits.hpp>
    
    struct Foo {
      virtual ~Foo() = default;
    };
    struct Bar : public Foo {};
    struct Qux : public Foo {};
    
    template<class T>
    void f1(T f2, Foo &foo) {
      // dynamically cast foo to type of f2's argument
      f2(dynamic_cast<typename boost::function_traits<decltype(*f2)>::arg1_type&>(foo));
    }
    
    int main() {
      Bar bar;
      Qux qux;
      f1(+[](Bar &bar) {}, bar);
      f1(+[](Qux &qux) {}, qux); // works now!
    }