简体   繁体   中英

Overloading rvalue/const lvalue for pointer

I'm using gcc 4.8.4.

The following code fails with a compiler error from line 22 (indicated):

invalid initialization of reference of type 'int*&&' from expression of type 'int* const'

Why isn't the call to square(ptr) using the lvalue version of square ?

#include <iostream>
#include <memory>

int square(int* &&num) {
    std::cout << "rvalue" << std::endl;
    std::unique_ptr<int> x(num);
    const auto ptr = x.get();
    return square(ptr);  // this is line 22
}

int square(const int* &num) {
    std::cout << "lvalue" << std::endl;
    return (*num) * (*num);
}

int main() {
    std::unique_ptr<int> up(new int);
    *up = 5;
    std::cout << square(up.release()) << std::endl;
}

You have order problem:

return square(ptr);

only see int square(int* &&num) declaration and is invalid

And int square(const int* &num) sould be int square(int*const &num) .

Fixed version .

At line 22, the only definition of square() in scope is the one that takes an rvalue reference - int square(int* &&) . ptr is an lvalue, so the error message explains the difference in type.

If you swap the order of the function definitions so that int square(const int* &) is also in scope, you'll still get the same error. That is because you have a pointer to a mutable int , so the lvalue function is still not a candidate.

You can change that to accept a const reference to a pointer to int:

int square(int *const& num) {
    std::cout << "lvalue" << std::endl;
    return (*num) * (*num);
}

And now the program compiles and runs.

Obviously, this can be simplified to accept num by value, but I'm guessing you want to make this work with something more heavyweight than int .

Rewritten example

#include <iostream>
#include <memory>

int square(int *const& num) {
    std::cout << "lvalue" << std::endl;
    return *num * *num;
}

int square(int*&& num) {
    std::cout << "rvalue" << std::endl;
    std::unique_ptr<int> x(num);
    const auto ptr = x.get();
    return square(ptr);
}

int main() {
    auto up = std::make_unique<int>(5);
    std::cout << square(up.release()) << std::endl;
}

As a side note, I try to avoid unique_ptr::release() - it can be useful when interfacing with pre-C++11 code that takes ownership of naked pointers, but it's hard to reason about it without following the code in detail. Modern code should prefer to pass the smart pointer:

int square(std::unique_ptr<int>&& x) {
    std::cout << "rvalue" << std::endl;
    const auto ptr = x.get();
    return square(ptr);
}

int main() {
    auto up = std::make_unique<int>(5);
    std::cout << square(std::move(up)) << std::endl;
}

Here, it's much clearer that square() will take ownership of its argument.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM