lundi 3 mai 2021

Why is std::forward turning my lvalue into an rvalue?

template<class T>
struct IntHolder {
    T i;
};

template<class T>
void addOne(T& t) {
    t.i += 1;
}

template<class... Args>
void addAll(Args... args) {
      // Magic to run addOne on each arg
      int dummy[] = { 0, ((void)addOne(std::forward<Args>(args)), 0)... };
}

int main() {
    IntHolder<int> x{2};
    IntHolder<double> t{3};
    addAll(x, t);
    return 0;
}

This toy example won't compile because

prog.cc: In instantiation of 'void addAll(Args ...) [with Args = {IntHolder<int>, IntHolder<double>}]':
prog.cc:60:16:   required from here
prog.cc:54:39: error: invalid initialization of non-const reference of type 'IntHolder<int>&' from an rvalue of type 'IntHolder<int>'
       int dummy[] = { 0, ((void)addOne(std::forward<Args>(args)), 0)... };
                                       ^
prog.cc:48:6: note:   initializing argument 1 of 'void addOne(T&) [with T = IntHolder<int>]'
 void addOne(T& t) {

What I thought would happen here is that addAll gets two lvalues passed in, and then addOne would be called on each of those as an lvalue. However, it seems somewhere along the way, the compiler thinks that the argument is getting converted to an rvalue. Why might this be?

Aucun commentaire:

Enregistrer un commentaire