Могу ли я иметь шаблонную функцию с переменным значением, возвращающую разные типы?
Я делаю некоторую десериализацию из байтового массива и сделал шаблон 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 ответа
Возможно, что-то в этом роде:
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
для каждого типа, который вы хотите поддержать, оставлено в качестве упражнения для читателя.
Спасибо, Бен и Сеф из #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)));
}
который делает именно то, что я хотел. Я думаю, что это можно сделать немного более производительным, но это не требуется для моего приложения на данный момент. Ура!