Как переслать значения кортежа? std :: get (move (tuple)) против вперед (std :: get (tuple)) - PullRequest
1 голос
/ 26 марта 2020

Предположим, вы пишете что-то вроде класса "initializer", в котором хранит набор значений (включая ссылки). Эти значения затем используются для инициализации заданного типа (например, через my_initializer.initialize<Foo>():

template<typename... Values>
struct Initializer{
    std::tuple<Values...> values;

    template<typename TypeToInitialize, std::size_t... Is>
    TypeToInitialize initialize_implementation( std::index_sequence<Is...> ){
        return { std::get<Is>( this->values )... };
    }

    template<typename TypeToInitialize>
    TypeToInitialize initialize(){
        return initialize_implementation( std::make_index_sequence<sizeof...(Values)>() );
    }
};

Довольно простой диван. Однако теперь я хочу предоставить перегрузку initialize() для rvalue объекты, которые вызываются при каждом вызове объекта, это rvalue , и вызов initialize<...>() является последним действием перед уничтожением объекта.

Как переслать значения кортежа? Какой вариант следует использовать?

template<typename TypeToInitialize, std::size_t... Is>
TypeToInitialize initialize_move_implementation( std::index_sequence<Is...> )
{
    // OPTION 1
    return { std::forward<Values>( std::get<Is>( this->values ) )... };

    // OPTION 2
    return { std::get<Is>( std::move( this->values ) )... };
}

template<typename TypeToInitialize>
TypeToInitialize initialize() && {
    return initialize_move_implementation<TypeToInitialize>( std::make_index_sequence<sizeof...(Values)>() );
}

Ответы [ 2 ]

2 голосов
/ 26 марта 2020
template<typename TypeToInitialize>
TypeToInitialize initialize() && {
    return std::make_from_tuple<TypeToInitialize>(this->values);
}

Внутренне он выполняет что-то вроде:

return T(std::get<I>(std::forward<Tuple>(t))...);

Где I - это индексная последовательность, как в вашем первоначальном примере.

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

Если сохраненное значение имеет тип T или T&& (предположим, T - это тип объекта), оба параметра дают T&&; если сохраненное значение имеет тип T&, оба параметра дают T&, поэтому я не думаю, что между этими двумя вариантами есть разница. Мне лично нравится вариант 2, потому что forward обычно используется вместе с универсальными ссылками для пересылки аргументов функции в другую функцию, тогда как здесь вы пересылаете значения, хранящиеся в члене класса, что может немного сбивать с толку.

...