У меня есть полиморфные классы Base
, Derived1
и Derived2
.
я хочу сделать
bool b = typeid(*base) == typeid(Derived1);
dynamic_cast<typename std::conditional<b, Derived1*, Derived2*>::type>(base)
Мой компилятор говорит, что b
не является выражением времени компиляции (и я понимаю, что это значит). Есть ли способ решить проблему?
Каким должен быть тип этого выражения?
if (b) .. else ....
вместо std::conditional
.
Компилятор не может принимать решения во время компиляции на основе информации, доступной только во время выполнения.
@TedLyngmo на самом деле они хотят использовать средство времени компиляции для принятия решения во время выполнения. std::conditional
здесь просто неправильный инструмент
@ 463035818_is_not_a_number Да, это был std::conditional
, на который я отреагировал. Ваш if (b) ... else ...
— правильный ответ — или избегайте его, используя полиморфизм времени выполнения, как предлагает BoP ниже.
Обычное решение состоит в том, чтобы иметь виртуальную функцию в Base, которую производные классы затем реализуют по-разному. Возможно, вам не нужно знать точный тип?
Мне любопытно, как вы оказались в использовании std::conditional
.
Ребята, я прошу эквивалент std::conditional во время выполнения, а не для if-else или виртуального создателя :(
Непонятно, что вообще должна означать эта фраза "std::conditional runtime эквивалент". Вам нужна функция с типом возвращаемого значения, зависящим от некоторого значения времени выполнения? Это называется "зависимый тип" (погуглите), в С++ их нет.
"std::условный эквивалент времени выполнения" - это if-else. Непонятно, почему вы ищете что-то другое. С++ не изобрел ничего нового, потому что if-else просто отлично. Если вы думаете, что это не так, вам нужно сказать, почему
Здесь не нужно std::conditional
. Поскольку вы выполняете динамическое приведение, это приведение в любом случае происходит во время выполнения, поэтому нет смысла пытаться втиснуть его во время компиляции. Просто удалите std::conditional
и проблема исчезнет:
if (b)
dynamic_cast<Derived1*>(base)
else
dynamic_cast<Derived2*>(base)
Обратите внимание, что этот код такой же псевдо, как и ваш, и высока вероятность того, что вам вообще не нужен приведение типов. Может быть, вы и делаете, но без контекста я предполагаю, что вам скорее нужна виртуальная функция.
Более того, bool b = typeid(*base) == typeid(Derived1);
выглядит так, как будто вы хотите использовать Derived1*
только тогда, когда бросок завершится успешно. Однако dynamic_cast
уже сообщает вам, когда приведение не может быть выполнено путем возврата nullptr
.
Если вы ищете способ «скрыть» приведение в функции, это не сработает. Если вы напишете base* my_cast(auto* x)
, как вы упомянули в комментарии, он всегда будет возвращать base*
независимо от того, что вы используете внутри функции:
#include <iostream>
#include <type_traits>
struct base {
virtual ~base() {}
void hello() { std::cout << "base\n";} // not virtual
};
struct derived : base {
void hello() { std::cout << "derived\n";}
};
base* foo(auto* b) {
auto d = dynamic_cast<derived*>(b); // cast to derived
d->hello();
return d; // and return
}
int main() {
base b;
auto x = foo(&b);
std::cout << std::is_same<base*,decltype(x)>::value << "\n";
std::cout << std::is_same<derived*,decltype(x)>::value << "\n";
x->hello();
}
derived
1
0
base
Я пытаюсь избежать if-else в этом случае, потому что я верю, что есть лучший способ сделать это. Типа, мы в с++, разве нет ничего лучше, чем if-else? Поэтому я прошу std::условный эквивалент времени выполнения
@FlufflePuff, почему ты думаешь, что if -else
недостаточно хорош? Если вы объясните, что, по вашему мнению, в ней плохо, возможно, мы найдем что-нибудь получше, но я не вижу в этом ничего плохого.
Я кодирую сериализатор для графического движка. У меня есть WorldEngineObject
(базовый чистый виртуальный класс, сокращенно WEO), skybox
и dimensional
, которые являются производными от WEO. Итак, я хочу написать (псевдокод): void s(dimensional* d);
void s(skybox* s);
void serialize(vector<WEO*> * obj) { foreach(o in obj) s(dynamic_cast< "is actual type skybox?", "if yes, cast to skybox" "else cast to dimensional">(o)); }
тогда он выбирает одну из перегруженных функций. И я хочу избежать if-else, потому что считаю, что есть лучший способ сделать это.
@FlufflePuff, что именно вы имеете в виду под «лучше»?
Более элегантный, более гениальный
if (b) ... else ...
очень элегантно имхо. Парень, который изобрел if/else
, должно быть, гений. Серьезно, я до сих пор понятия не имею, что вы ищете. Стремление написать умный код обычно заканчивается кодом, который никто не хочет читать. if/else
это просто, это работает, так что не так?
Я нашел идеальное решение. f( get_type(obj) )
и auto* get_type(auto* obj) { if (...) return "cast to skybox"; else return "cast to dimensional" ; }
это меня успокоило
@FlufflePuff это не работает так, как вы хотите, чтобы это работало. auto
не будет волшебным образом подстраиваться под нужный тип в зависимости от условий выполнения
Это псевдокод, так что auto
это хороший способ не усложнять его (имхо)
@FlufflePuff ... но тогда вы на самом деле просто делаете то, что предлагается в этом ответе? Когда вы выполнили приведение к skybox
или dimensional
, что вы возвращаете из функции?
@FlufflePuff, но нет типа возвращаемого значения, которое вы могли бы заменить auto
, чтобы функция возвращала правильный тип в зависимости от условия, функция может иметь только один возвращаемый тип, определенный во время компиляции
Если возвращаемый тип функции — Base*, мы можем инициализировать его с помощью Derived*, который будет фактическим типом значения (мы все помним об абстрактных фабриках). так вот что я делаю вместо auto
@FlufflPuff, поэтому вы приводите внутри функции либо к Derived1*
, либо к Derived2*
, а затем по возвращении из функции происходит неявное преобразование в Base*
. Если это то, что вы хотите, то я совсем запутался, такая функция бесполезна
Эта функция - способ скрыть If-else, это то, что я искал
@FlufflePuff не только скрывает if-else, но и возвращает Base*
, что делает приведение внутри функции бессмысленным. Независимо от того, что вы используете, функция всегда будет возвращать указатель на Base
godbolt.org/z/sPPe5YqGq
@FlufflePuff Может быть, вы хотели изобрести полиморфизм времени выполнения в C++ и обнаружили, что это уже основная функция?
Что такое
base
?