微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决动态转换为函数参数类型 (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{...}};

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。