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衰减为函数指针。只有当lambdaf2
只有一个参数,并且没有任何捕获时,这才起作用。我努力使用有状态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(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!
}