Я знаю, что нельзя иметь виртуальную функцию шаблона-члена, но мне нужно что-то похожее на нее.Функция виртуального шаблона-члена
Рассмотрим следующий псевдокод:
struct abstract
{
template<typename T>
virtual T get() const = 0;
};
using abstract_pointer = std::shared_ptr<abstract>;
struct concrete_int : public abstract
{
template<>
int get() const { return 123; }
};
struct concrete_string : public abstract
{
template<>
std::string get() const { return "abc"; }
};
abstract_pointer factory()
{
// Some logic here to decide what concrete type to return
return ...;
}
void print_value(abstract_pointer p)
{
// Will print either 123 or "abc"
std::cout << "p = " << p->get() << '\n';
}
int main()
{
abstract_pointer p = factory();
print_value(p);
}
Основной код будет использовать только abstract_pointer
тип, он не должен действительно ничего знать о конкретных классов.
Его можно легко решить с помощью CRTP и вывода типа, но тогда невозможно передать объект другим функциям, как в приведенном выше примере.
Я мог бы также использовать вариант Boost или союзы, но тогда он может быстро стать громоздким, если добавить более конкретные классы. Я мог бы также использовать Boost, но тогда мне пришлось бы использовать any_cast
, и это было бы не так ... ну, nice и просто.
Может быть, сегодня мой google-fu плохой, или я просто слишком устал, но я действительно не нашел никакого способа обойти его. Можно ли сделать что-то вроде этого, сохраняя при этом его достаточно гибким, чтобы добавлять более конкретные классы, а также поддерживать интерфейс простым и приятным?
Небольшое пояснение о прецеденте: Это должно быть частью небольшого лексического анализатора для простого компилятора я делаю (просто для удовольствия, хотя), и абстрактный класс в приведенном выше примере класс «токен», а конкретные классы - это конкретные токены, такие как «цельный токен» или «токен строки» или «токен идентификатора».
Причина, по которой я хочу использовать абстрактные/конкретные классы и наследование, заключается в том, что я хочу, чтобы lexer был достаточно гибким, чтобы использоваться несколькими языками, поэтому должно быть легко, например, добавить дочерний токен идентификатора класс для «ключевого слова» и, возможно, даже один конкретный класс для каждого ключевого слова.
Но, возможно, AaronI прав, я стараюсь сделать что-то сложное. Я позволю этому вопросу встать на тот случай, если кто-нибудь придумает хорошее решение или найдет хороший дубликат, тем временем я подумаю об этом и посмотрю, смогу ли я придумать что-то приемлемое.
Всякий раз, когда мне это нужно, я прибегал к CRTP. Однако даже CRTP позволяет иметь абстрактные (не templated) базовые классы, чтобы упростить их передачу. Я использовал этот подход в значительной степени с помощью моей [государственной системы состояний STTCL] (https://github.com/makulik/sttcl). –
Возможно, проверьте Boost.TypeErasure? –
не может абстрактный объект просто поддерживать посещение? Трудно понять это требование, не зная случая использования. –