【发布时间】:2017-10-23 22:25:12
【问题描述】:
这是与Using std::forward on sub fields 类似的问题,但那里的答案似乎不适用于我的情况。
template<class Base, class F>
void visit(Base&&, const F&) {
throw std::bad_cast();
}
template<class Derived, class... Rest, class Base, class F>
void visit(Base&& base, const F& f) {
if (auto *as_derived = dynamic_cast<Derived *>(&base)) {
return f(std::forward<Base>(*as_derived));
} else {
return visit<Rest...>(std::forward<Base>(base), f);
}
}
我的目标是使以下测试用例起作用:
struct Animal {
virtual ~Animal() {}
};
struct Cat : Animal {
void speak() & { puts("meow"); }
void yowl() && { puts("MEOW!"); }
};
struct Dog : Animal {
void speak() & { puts("woof"); }
void yowl() && { puts("WOOF!"); }
};
int main() {
Animal *a = new Cat();
Animal *b = new Dog();
visit<Cat, Dog>(*a, [](auto&& a){ std::forward<decltype(a)>(a).speak(); });
visit<Cat, Dog>(*b, [](auto&& a){ std::forward<decltype(a)>(a).speak(); });
visit<Cat, Dog>(std::move(*a), [](auto&& a){ std::forward<decltype(a)>(a).yowl(); });
visit<Cat, Dog>(std::move(*b), [](auto&& a){ std::forward<decltype(a)>(a).yowl(); });
}
期望的输出:“喵”“汪”“喵!” “纬!”。请注意,speak 和 yowl 函数是非虚拟的;这在我的原始代码中是必需的,因为它们实际上是模板,并且模板不能是虚拟的。
这里写的这段代码的问题是std::forward<Base>(*as_derived) 不只是改变*as_derived 上的ref-qualifiers 和const-qualifiers 来启用完美转发;它实际上将 type 转换回 Base&,削弱了 visit 的全部意义!
是否有一个标准库函数可以完成我想要 std::forward 做的事情 - 即更改 *as_derived 上的 ref-qualifiers 和 const-qualifiers 以匹配那些完美的——从std::forward<Base>向前推导出来?
如果没有标准库函数,我怎么写一个“完美转发子类型”的函数供自己使用?
上面的 Wandbox 链接包含一些对这个测试用例“有效”的东西,但它没有保留 constness,而且看起来一点也不优雅。
【问题讨论】:
标签: c++ c++14 visitor-pattern perfect-forwarding