如何解决动态转换为函数参数类型 (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 似乎是无状态的,这意味着您可以:
- 使用免费功能。
- 使用
+
操作将(无状态)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 举报,一经查实,本站将立刻删除。