В настоящее время я портирую некоторый код из версии CT ANTLR4 на цель C ++, и в настоящее время я сталкиваюсь с некоторыми проблемами. Я построил свой AST в C # так, чтобы создать базовый класс (назовем его Base) и производные классы (назовем его Derived) с виртуальными функциями, которые я могу использовать для реализации указанных классов.
Однако, пытаясь преобразовать этот код в C ++, я продолжаю получать исключения bad_cast
Я сузил его до antlrcpp :: Any, который неправильно переводит производный класс в его базовый класс. Например:
class Base {
public:
virtual std::string ToString() const { return "Base\n"; }
};
class Derived : public Base {
public:
std::string ToString() const override { return "Derived\n"; }
};
int main() {
Derived value;
std::cout << value.ToString(); //Obviously prints out Derived
Base& base_value = value;
std::cout << base_value.ToString(); //Still works exactly as expected and prints Derived
auto any = antlrcpp::Any(value);
auto derived = any.as<Base>(); //internally uses a dynamic_cast and throws a bad_cast
std::cout << derived.ToString(); //never gets to here
}
Первоначально я думал, что это может быть, потому что он работал только с указателями, однако
auto any = antlrcpp::Any(new Derived());
std::cout << any.as<Base*>()->ToString(); //throws bad_cast
Я изменил dynamic_cast
в static_cast
внутри заголовка, и он будет разыгрываться, однако он печатает «Base». А прямое приведение в стиле C вызывает сбой при доступе к любому элементу данных.
Как именно я использую antlrcpp::Any
получить базовый класс? Есть ли что-то очевидное, что мне не хватает?
И если это невозможно, как именно я могу обойти это? Есть метод .is (), однако во многих случаях проверка на возвращаемое значение посетителя определенного типа просто неосуществима (например, с выражениями может быть 30-40 операторов).
antlrcpp::any
класс не предназначен для такого сценария. Это не универсальная реализация варианта.
Если вам нужно, вы должны подумать о собственной реализации Variant, использующей объединение для различных типов и т. Д., Которая не работает с стиранием типов.
Уникальные указатели, вероятно, не очень хорошая идея в этом контексте в целом, так как они не поддерживают семантику копирования (и вам это понадобится здесь). Для оценки с посетителями лучше пойти с shared_ptr
вместо.
Других решений пока нет …