我想實現一個使用lambdas而不實現類的多態訪問者。我已經有了一個基礎,但是我正在努力爲我的lambda的參數扣除類型。帶lambda的多態訪問者
比方說,我有一些遺留代碼庫,決定使用類型標籤多態類型,像這樣:
enum class ClassType
{
BaseType = 0, TypeA, TypeB
};
class BaseType
{
public:
virtual ~BaseType() {}
ClassType getType() const
{ return type; }
protected:
ClassType type;
};
class TypeA : public BaseType
{
public:
static const ClassType Type = ClassType::TypeA;
explicit TypeA(int val) : val(val)
{ type = ClassType::TypeA; }
virtual ~TypeA() {}
int val;
};
class TypeB : public BaseType
{
public:
static const ClassType Type = ClassType::TypeB;
explicit TypeB(std::string s) : s(s)
{ type = ClassType::TypeB; }
virtual ~TypeB() {}
std::string s;
};
我想實現的是類似std::variant
遊客那麼看起來像一個遊客這樣的:
std::vector<BaseType*> elements;
elements.emplace_back(new TypeA(1));
elements.emplace_back(new TypeB("hello"));
for (auto elem : elements)
{
visit(elem,
[](TypeA* typeA) {
std::cout << "Found TypeA element, val=" << typeA->val << std::endl;
},
[](TypeB* typeB) {
std::cout << "Found TypeB element, s=" << typeB->s << std::endl;
}
);
}
我至今未能實現這樣的功能visit<>()
做法是下面的代碼:
template <typename T>
struct identity
{
typedef T type;
};
template <typename T>
void apply_(BaseType* b, typename identity<std::function<void(T*)>&>::type visitor)
{
if (b->getType() != T::Type)
return;
T* t = dynamic_cast<T*>(b);
if (t) visitor(t);
}
template <typename... Ts>
void visit(BaseType* b, Ts... visitors) {
std::initializer_list<int>{ (apply_(b, visitors), 0)... };
}
編譯器抱怨說它不能推導出我的apply_
函數的模板參數T
。
我該如何聲明apply_
的正確模板和函數簽名才能正確捕獲lambda表達式,甚至可能還有其他可調用的對象?或者甚至可能是這樣的?
lamdba不是'std :: function'。 – Jarod42
有了一些函數特徵,你可以從'operator()'中檢索參數,假設沒有超載,沒有'auto'。 – Jarod42
順便說一句,如果你寫了一個真正的訪問者模式,你可能有一種方法來創建你的訪問者,就像你爲訪問做的那樣。 – Jarod42