lundi 27 août 2018

Why doesn't raw curly constructor {} return an rvalue?

Lets say you have a variadic class with a tuple, that can be move constructed with args + 1 new arg. When constructed using std::apply and a raw curly brace constructor, that constructor doesn't return an rvalue. Which means the class isn't move constructed. An example follows to clarify.

#include <cstdio>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <vector>

template <class... Args>
struct icecream {
    icecream() = default;

    template <class... MoreArgs>
    icecream(icecream<MoreArgs...>&& ice) {
        std::apply(
                [this](auto&&... ds) {
                    data = { std::move(ds)..., {} };
                },
                std::move(ice.data));
    }

    // This works :

    // template <class... MoreArgs>
    // icecream(icecream<MoreArgs...>&& ice) {
    //  std::apply(
    //          [this](auto&&... ds) {
    //              data = { std::move(ds)...,
    //                  std::move(std::vector<double>{}) };
    //          },
    //          std::move(ice.data));
    // }

    std::tuple<std::vector<Args>...> data{};
};

int main(int, char**) {
    icecream<int> miam;
    std::get<0>(miam.data).push_back(1);
    std::get<0>(miam.data).push_back(2);

    icecream<int, double> cherry_garcia{ std::move(miam) };

    printf("miam : \n");
    for (const auto& x : std::get<0>(miam.data)) {
        printf("%d\n", x);
    }

    printf("\ncherry_garcia : \n");
    for (const auto& x : std::get<0>(cherry_garcia.data)) {
        printf("%d\n", x);
    }

    return 0;
}

The output is :

miam : 
1
2

cherry_garcia : 
1
2

The example is a little dumbed down, but illustrates the point. In the first move constructor, {} is used and the tuple copy constructs. If you uncomment the second constructor with a hardcoded std::move, then it works.

I test on VS latest, clang latest and gcc latest. All have the same result. (wandbox : https://wandbox.org/permlink/IQqqlLcmeyOzsJHC )

So the question is, why not return an rvalue? I'm obviously missing something with the curly constructor. This might have nothing to do with the variadic stuff, but I thought I might as well show the real scenario.

Aucun commentaire:

Enregistrer un commentaire