Могу ли я иметь шаблонную функцию с переменным значением, возвращающую разные типы? - PullRequest
0 голосов
/ 23 сентября 2018

Я делаю некоторую десериализацию из байтового массива и сделал шаблон Variaad ExtractData, чтобы он работал как

QByteArray data; // (this works just like std::vector<char>)
std::vector<std::any> values = ExtractData<float, char>(data); // read a float, char sequentially from data
float readFloat = std::any_cast<float>(values[0]);
float readChar = std::any_cast<char>(values[1]);

, но все же, много шаблонного кода для декодирования.
В идеале я бы хотелчто-то вроде

float readFloat;
char readChar;
std::tie(readFloat, readChar) = ExtractData<float, char>(data);

Структура ExtractData в основном

using anyVec = std::vector<std::any>;

// one type resolution
template<typename T>
anyVec ExtractData(const QByteArray& data, anyVec out = {}){
    // extract T value, assign to std::any, push_back into out
    return outVec;
}

// multiple types resolution
template<typename T, typename... Rest>
typename std::enable_if<(sizeof...(Rest) > 0), anyVec>::type
ExtractData(const QByteArray& data, anyVec out = {}){
    // extract T value, assign to std::any, push_back into out
    return ExtractData<Rest...>(data, out);
}

Я просто не понимаю, как заставить ExtractData<type1, type2, ...>(data) вернуть std::tuple<type1, type2, ...>, так как вся эта исходная информация о типе потерянакогда список типов шаблонов "раскручивается".Это вообще возможно?Извините, если я упускаю что-то очевидное, я все еще довольно плохо знаком с c ++ 11 и новее.

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


Я использую Qt 5.11, c ++ 14 (здесь опущено experimental в пространствах имен), но также рад слышать советы по c ++ 17.Точный фрагмент кода, который я использую: https://gist.github.com/tjakubo2/dc3e6897bf42f3bed78933031e53786b

Ответы [ 2 ]

0 голосов
/ 23 сентября 2018

Благодаря пристанищу, Бен и Сеф с сервера #include Discord, как Игорь предложил в ответе здесь, я приземлился с:

template<typename T>
std::tuple<T> ExtractSingle(const QByteArray& data, size_t offset){
    // pull T_val from data at given offset
    return std::tuple<T>{T_val};
}

template<typename T>
std::tuple<T> ExtractData(const QByteArray& data, size_t offset = 0){
    return ExtractSingle<T>(data, offset);
}

template<typename T, typename... Rest>
typename std::enable_if<(sizeof...(Rest) > 0), std::tuple<T, Rest...>>::type
ExtractData(const QByteArray& data, size_t offset = 0){
    auto val = ExtractSingle<T>(data, offset);
    return std::tuple_cat(std::move(val), ExtractData<Rest...>(data, offset + sizeof(T)));
}

, который делает именно то, что я хотел.Я думаю, что это можно сделать немного более производительным, но это не нужно для моего приложения на данный момент.Ура! * * 1005

0 голосов
/ 23 сентября 2018

Что-то в этом роде, возможно:

template <typename T>
T ExtractOnePiece(const QByteArray& data, int& offset);

template <typename... Ts>
std::tuple<Ts...> ExtractData(const QByteArray& data) {
    int offset = 0;
    return {ExtractOnePiece<Ts>(data, offset)...};
}

Демо .Специализации ExtractOnePiece для каждого типа, который вы хотите поддерживать, оставлены в качестве упражнения для читателя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...