Стандартная среда выполнения::условная

У меня есть полиморфные классы Base, Derived1 и Derived2.

я хочу сделать

bool b = typeid(*base) == typeid(Derived1);

dynamic_cast<typename std::conditional<b, Derived1*, Derived2*>::type>(base)

Мой компилятор говорит, что b не является выражением времени компиляции (и я понимаю, что это значит). Есть ли способ решить проблему?

Что такое base?

tadman 12.04.2023 18:18

Каким должен быть тип этого выражения?

n. m. 12.04.2023 18:18
if (b) .. else .... вместо std::conditional.
463035818_is_not_a_number 12.04.2023 18:18

Компилятор не может принимать решения во время компиляции на основе информации, доступной только во время выполнения.

Ted Lyngmo 12.04.2023 18:19

@TedLyngmo на самом деле они хотят использовать средство времени компиляции для принятия решения во время выполнения. std::conditional здесь просто неправильный инструмент

463035818_is_not_a_number 12.04.2023 18:20

@ 463035818_is_not_a_number Да, это был std::conditional, на который я отреагировал. Ваш if (b) ... else ... — правильный ответ — или избегайте его, используя полиморфизм времени выполнения, как предлагает BoP ниже.

Ted Lyngmo 12.04.2023 18:20

Обычное решение состоит в том, чтобы иметь виртуальную функцию в Base, которую производные классы затем реализуют по-разному. Возможно, вам не нужно знать точный тип?

BoP 12.04.2023 18:21

Мне любопытно, как вы оказались в использовании std::conditional.

463035818_is_not_a_number 12.04.2023 18:34

Ребята, я прошу эквивалент std::conditional во время выполнения, а не для if-else или виртуального создателя :(

Fluffle Puff 12.04.2023 20:18

Непонятно, что вообще должна означать эта фраза "std::conditional runtime эквивалент". Вам нужна функция с типом возвращаемого значения, зависящим от некоторого значения времени выполнения? Это называется "зависимый тип" (погуглите), в С++ их нет.

n. m. 12.04.2023 21:06

"std::условный эквивалент времени выполнения" - это if-else. Непонятно, почему вы ищете что-то другое. С++ не изобрел ничего нового, потому что if-else просто отлично. Если вы думаете, что это не так, вам нужно сказать, почему

463035818_is_not_a_number 12.04.2023 21:25
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
11
93
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Здесь не нужно 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::условный эквивалент времени выполнения

Fluffle Puff 12.04.2023 20:16

@FlufflePuff, почему ты думаешь, что if -else недостаточно хорош? Если вы объясните, что, по вашему мнению, в ней плохо, возможно, мы найдем что-нибудь получше, но я не вижу в этом ничего плохого.

463035818_is_not_a_number 12.04.2023 20:39

Я кодирую сериализатор для графического движка. У меня есть 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, потому что считаю, что есть лучший способ сделать это.

Fluffle Puff 13.04.2023 08:30

@FlufflePuff, что именно вы имеете в виду под «лучше»?

463035818_is_not_a_number 13.04.2023 08:40

Более элегантный, более гениальный

Fluffle Puff 13.04.2023 08:52
if (b) ... else ... очень элегантно имхо. Парень, который изобрел if/else, должно быть, гений. Серьезно, я до сих пор понятия не имею, что вы ищете. Стремление написать умный код обычно заканчивается кодом, который никто не хочет читать. if/else это просто, это работает, так что не так?
463035818_is_not_a_number 13.04.2023 08:58

Я нашел идеальное решение. f( get_type(obj) ) и auto* get_type(auto* obj) { if (...) return "cast to skybox"; else return "cast to dimensional" ; } это меня успокоило

Fluffle Puff 13.04.2023 14:31

@FlufflePuff это не работает так, как вы хотите, чтобы это работало. auto не будет волшебным образом подстраиваться под нужный тип в зависимости от условий выполнения

463035818_is_not_a_number 13.04.2023 15:24

Это псевдокод, так что auto это хороший способ не усложнять его (имхо)

Fluffle Puff 13.04.2023 17:03

@FlufflePuff ... но тогда вы на самом деле просто делаете то, что предлагается в этом ответе? Когда вы выполнили приведение к skybox или dimensional, что вы возвращаете из функции?

Ted Lyngmo 13.04.2023 17:11

@FlufflePuff, но нет типа возвращаемого значения, которое вы могли бы заменить auto, чтобы функция возвращала правильный тип в зависимости от условия, функция может иметь только один возвращаемый тип, определенный во время компиляции

463035818_is_not_a_number 13.04.2023 17:20

Если возвращаемый тип функции — Base*, мы можем инициализировать его с помощью Derived*, который будет фактическим типом значения (мы все помним об абстрактных фабриках). так вот что я делаю вместо auto

Fluffle Puff 13.04.2023 20:18

@FlufflPuff, поэтому вы приводите внутри функции либо к Derived1*, либо к Derived2*, а затем по возвращении из функции происходит неявное преобразование в Base*. Если это то, что вы хотите, то я совсем запутался, такая функция бесполезна

463035818_is_not_a_number 13.04.2023 20:22

Эта функция - способ скрыть If-else, это то, что я искал

Fluffle Puff 14.04.2023 10:08

@FlufflePuff не только скрывает if-else, но и возвращает Base*, что делает приведение внутри функции бессмысленным. Независимо от того, что вы используете, функция всегда будет возвращать указатель на Basegodbolt.org/z/sPPe5YqGq

463035818_is_not_a_number 14.04.2023 11:15

@FlufflePuff Может быть, вы хотели изобрести полиморфизм времени выполнения в C++ и обнаружили, что это уже основная функция?

Ted Lyngmo 15.04.2023 05:39

Другие вопросы по теме