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

问题描述

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

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<Bar &>(foo));
}

int main() {
  Bar bar;
  Qux qux;
  f1([](Bar &bar) {},bar);
  f1([](Qux &qux) {},qux); // error here!
}

解决方法

这是模板化转换的作业operator

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});
}
,

我努力用推导的有状态 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));
}

http://coliru.stacked-crooked.com/a/61ceb268b0a5a443

,

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

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

然后在进行强制转换时使用它来确定 f2 的参数类型:

f2(dynamic_cast<decltype(arg(+f2))>(foo));

请注意,将 + 作为参数传递给 arg 时,会将 lambda 衰减为函数指针。这仅在 lambda f2 只有一个参数且没有任何捕获时有效。

,

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

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

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

  1. 使用免费功能。
  2. 使用 + 操作将(无状态)lambda 衰减为函数指针(tip,lambdas 衰减 (ab))。

一旦你接受了这一点,就很容易了; 您可以使用 Boost.TypeTraits 推导出函数的(现在唯一的)定义的参数。

#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!
}

https://godbolt.org/z/r1jf9n8Yf

如果你想要一个更通用的解决方案,你已经定义了一个带有内部或 sfinae 检测到的“第一个参数”的函数对象的协议。例如struct F{using arg1_type = ...; auto operator()(arg1_type) const{...}};

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...