這是一個類似於Using std::forward on sub fields的問題,但答案似乎並不適用於我的情況。在鑄造參數上使用std :: forward
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限定符來實現完美的轉發;它實際上會將類型備份到Base&
,削弱visit
的整點!
有沒有一個標準庫函數做什麼,我想std::forward
的事 - 即,更改*as_derived
裁判,預選賽和const修飾詞相匹配的那些將是完美的,從前方推導std::forward<Base>
?
如果沒有標準的庫函數,我怎麼能寫一個「完美的向前的子類型」函數供我自己使用?
上面的Wandbox鏈接包含了一些對這個測試用例「起作用」的東西,但它並不保留常量,並且它看起來並不優雅。
這比列舉所有cv-ref的東西好得多。 – Barry