Search code examples
c++templatesrvaluelvaluestdmove

No known conversion from 'A' to 'A &&' for 1st argument


I am new to r-values and l-values in C++. I was playing with it. I am not sure why the following code works:

class A {
    public:
    A() {
        std::cout<<"Constructor called"<<std::endl;
    }
    A(const A& a) {
        std::cout<<"Copy Constructor called"<<std::endl;
    }
};

template<typename T>
void printA(T&& b) {
    std::cout<<"Print method called"<<std::endl;
}

int main() {
    // your code goes here
    A a;
    printA(a);
    return 0;
}

but the code fails to compile, if I change printA method to the following:

void printA(A&& b) Below is the full code:

class A {
    public:
    A() {
        std::cout<<"Constructor called"<<std::endl;
    }
    A(const A& a) {
        std::cout<<"Copy Constructor called"<<std::endl;
    }
};

void printA(A&& b) {
    std::cout<<"Print method called"<<std::endl;
}

int main() {
    // your code goes here
    A a;
    printA(a);
    return 0;
}

The compiler throws following error:

candidate function not viable: no known conversion from 'A' to 'A &&' for 1st argument

I understand we can make the above code work, by converting l-value to r-value reference using std::move, but not sure why code I shared at the beginning of the post is working!

Can somebody tell me what I am doing wrong here? Thanks!


Solution

  • In this function template:

    template<typename T>
    void printA(T&& b) {
        std::cout<<"Print method called"<<std::endl;
    }
    

    T&& is a forwarding reference. This means it can bind to l-values, or r-values:

    A a;
    printA(a); // ok, l-value
    printA(A{}); // ok, r-value
    

    However, this is a regular function that takes exactly an r-value:

    void printA(A&& b) {
        std::cout<<"Print method called"<<std::endl;
    }
    

    and so can only be called with an r-value:

    A a;
    printA(a); // error, can't bind r-value to l-value
    printA(A{}); // ok, r-value