Как вывести возвращаемый тип в C++

Я хочу создать что-то вроде Variant на C++. На самом деле я хочу использовать шаблоны как можно меньше. Идея состоит в том, чтобы сохранить значение в union как с типом переменной, так и вернуть значение в соответствии с сохраненным типом.

Таким образом, тестовый код выглядит следующим образом:

#include <iostream>
#include <vector>
#include <cstring>
#include <typeinfo>
#include <typeindex>

using namespace std;

constexpr uint64_t mix(char m, uint64_t s)
{
    return ((s << 7) + ~(s >> 3)) + static_cast<uint64_t>(~m);
}

constexpr uint64_t _(const char* str)
{
    return (*str) ? mix(*str,_(str + 1)) : 0;
}

class Variant
{
public:
    template<typename T>
    Variant(T value):
        m_info(typeid(value))
    {
        std::memcpy(&m_val, &value, sizeof(T));
    }

    auto toValue() ->decltype(???) // what have I use here ???
    {
        switch(_(m_info.name()))
        {
            case _("b"):
                return m_val.bval;
            case _("i"):
                return m_val.ival;
            case _("d"):
                return m_val.dval;
            break;
        }

        return 0;
    }
    char cval;
    unsigned char ucval;

private:
    union Types
    {
        bool bval;
        int ival;
        double dval;
    } m_val;
    std::type_index m_info;
};

Использование:

int main()
{
    std::vector<Variant> arr = { 1, 2.2, true };
    for(auto &v: arr)
    {
        cout << "value is: " << v.toValue() << endl;
    }
    return 0;
}

Но decltype требует выражения в качестве параметра, и здесь я застрял. Какое выражение я употребил здесь?

Очевидно, вы пытаетесь получить функцию, тип возвращаемого значения которой выводится во время выполнения - это невозможно. Тип возвращаемого значения должен быть известен во время компиляции.

UnholySheep 16.03.2022 17:11

К сожалению, C++ так не работает. Типы всех объектов, включая типы возвращаемых функций, должны быть известны во время компиляции, а не во время выполнения. Это фундаментально для C++, и для этого не существует безопасного для типов обходного пути.

Sam Varshavchik 16.03.2022 17:12
typeinfo.name() не является портативным
463035818_is_not_a_number 16.03.2022 17:13

Вывод типа для возвращаемых типов не поддерживается в C++. Лучше всего написать отдельные toBool, toInt, toDouble или один template<typename T> T to(), специализированный для каждого типа, что позволит вам написать v.to<int>().

Thomas 16.03.2022 17:14

просто напоминание, уже есть std::variant и std::any, на случай, если вы захотите сделать это сами.

apple apple 16.03.2022 17:18

C++17 использует std::visit для решения этой проблемы с помощью std::variant. Это использует шаблон посетителя для решения этой проблемы.

NathanOliver 16.03.2022 17:19

Проблема, которую вы создаете, больше, чем код, который вы предлагаете здесь. Если бы на этот вопрос был дан ответ, и вы смогли получили бы auto x = v.toValue(); для компиляции, что бы вы тогда смогли сделать с x? Могли ли вы ожидать, что !!x будет таким же, как x? Не могли бы вы выразить x % 2? Вы не могли бы, потому что компилятор больше не знает, что такое тип x.

Drew Dormann 16.03.2022 17:20
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
106
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Согласно комментарию @UnholySheep, вы пытаетесь создать функцию, тип возвращаемого значения которой выводится во время выполнения, что просто невозможно. Тип возвращаемого значения должен быть известен во время компиляции. Так что вам придется изменить свой API. Здесь есть несколько разных вариантов.

Это похоже на std::variant, чей API-эквивалент вашего toValue() выглядит так:

std::get<double>(variant)
std::get<int>(variant)
std::get<bool>(variant)

Этот вызов функции std::get выдаст std::bad_variant_access, если вы попытаетесь получить значение неправильного типа. Вы могли бы сделать это здесь.

Другой вариант — извлечь тип union { bool, int, double } из класса Variant, чтобы вы могли использовать его в качестве возвращаемого типа. Тогда, вероятно, было бы целесообразно иметь еще один вызов функции, чтобы вызывающая сторона могла сказать во время выполнения, к какому типу относится объединение. Вы можете вернуть перечисление или просто вернуть свою переменную m_type для этого.

Да, это в основном то же решение, к которому я пришел. Только одна мысль не давала мне покоя. Я знаю сохраненный тип и могу вернуть соответствующее значение...

folibis 16.03.2022 17:56

Однако это не имеет значения, потому что вызывающая сторона не знает сохраненный тип, когда вызывает toValue. Так что им все равно придется звонить getType или как-то еще. То же самое и с std::variant, так как вам нужно вызвать std::holds_alternative<T>, чтобы проверить тип, прежде чем вы сможете безопасно вызвать std::get<T>.

Jan 16.03.2022 18:03

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