я могу инициализировать std :: tuple из векторного массива? - PullRequest
3 голосов
/ 20 марта 2020

У меня есть std :: vector, содержащий вариант класса. Я хочу построить кортеж с теми же данными. Это возможно? Обычные методы построения для кортежа кажутся довольно ограничительными.

                    //In reality, I'm using JUCE::var.
                    // SimpleVariant is here just to make the example code more explicit.
struct SimpleVariant
{
    SimpleVariant(int i) :                a(i), b("") {}
    SimpleVariant(const std::string& s) : a(0), b(s) {}

    operator int() const { return a; }
    operator std::string() const { return b; }

private:
    int a;
    std::string b;
};


template <typename... T>
struct VariantTuple
{
    VariantTuple(const std::vector<SimpleVariant>& v)
    {
        // how do I initialize the tuple here?
    }

private:
    std::tuple<T...> tuple;
};


        std::vector<SimpleVariant> v{ SimpleVariant(1),
                                      SimpleVariant(2),
                                      SimpleVariant("a") };

        VariantTuple<int, int, std::string> t (v);

Некоторые пояснения, основанные на комментариях:

Мне не нужен кортеж, чтобы соответствовать термину массива по термину или для вывода типов из данного массива. Я хочу взять данный массив, а затем извлечь варианты, которые соответствуют определенному типу. Так, например, учитывая приведенный выше массив v, я хотел бы иметь возможность построить VariantTuple<int, std::string> и сопоставить его с терминами "1" и "a". Это вводит множество других проблем, выходящих за рамки моего первоначального вопроса. Но сейчас меня интересует вопрос, возможно ли вообще построить кортеж на основе массива.

1 Ответ

1 голос
/ 20 марта 2020

Ну, я не уверен, что вы просите динамически определить количество векторных элементов и построить кортеж, что невозможно, но здесь вы go. Я использовал std::index_sequence для определения количества элементов кортежа в зависимости от размера аргумента VariantTuple. Для этого требуется C ++ 17, так как он использует сложенное выражение.

#include <initializer_list>
#include <string>
#include <vector>
#include <tuple>
#include <utility>
#include <type_traits>
#include <ostream>
#include <iostream>

struct SimpleVariant
{
    SimpleVariant(int i) :                a(i), b("") {}
    SimpleVariant(const std::string& s) : a(0), b(s) {}

    operator int() const {
        return a;
    }

    operator std::string() const {
        return b;
    }

    int a;
    std::string b;
};

template<typename V, size_t... dim, typename... Args>
auto populate_tuple(const V& vec, std::index_sequence<dim...>, const std::tuple<Args...>& t) {
    return std::make_tuple(static_cast<std::remove_reference_t<decltype(std::get<dim>(t))>>(vec.at(dim))...);
}

template<size_t... dim, typename... Args>
std::ostream& dump_tuple(std::ostream& out, const std::tuple<Args...>& tpl, std::index_sequence<dim...>) {
    ((out << std::get<dim>(tpl) << ","), ...);
    return out;
}

template<typename... T>
struct VariantTuple
{
    VariantTuple(const std::vector<SimpleVariant>& v) : tpl(populate_tuple(v, std::make_index_sequence<sizeof...(T)>{}, tpl)) {}

    template<typename... V>
    friend std::ostream& operator <<(std::ostream& out, const VariantTuple<V...>& vt) {
        return dump_tuple(out, vt.tpl, std::make_index_sequence<sizeof...(V)>{});
    }
private:
    std::tuple<T...> tpl;
};

int main() {
    std::vector<SimpleVariant> v { 
        SimpleVariant(1),
        SimpleVariant(2),
        SimpleVariant("a") 
    };
    VariantTuple<int, int, std::string> t (v);
    std::cout << t << std::endl;

    return 0;
}
...