Search code examples
c++boostrvalue-reference

Boost:any rvalue vs lvalue overload resolution


I want to have function overloading, with the functions accepting boost::any lvalue and boost::any rvalue as arguments and exhibiting different behaviour based on that. A minimum reproducible example;

#include <boost/any.hpp>
#include <iostream>
#include <string>
#include <memory>

class MyClass {
 public:
  MyClass() {
   a_int = -1;
   b_string = "abc";
  }

 private:
  int a_int;
  std::string b_string;

 public:
  static void DumpMyClass(boost::any&& my_class_obj) {
    std::cout << "rvalue reference" << std::endl;
  }

  static void DumpMyClass(const boost::any& my_class_obj) {
    std::cout << "lvalue reference" << std::endl;
  }

};

int main() {
  std::shared_ptr<MyClass> c_sptr = std::make_shared<MyClass>();
  MyClass::DumpMyClass(c_sptr);
  MyClass::DumpMyClass(std::move(c_sptr));
  return 0;
}

The output that I see is this;

$clang++ -std=c++11 any.cc -o code && ./code
rvalue reference
rvalue reference

I was hoping that the call MyClass::DumpMyClass(c_sptr); would have used the function which prints 'lvalue reference'. The behaviour is as per expectation if I change function signatures to have parameters of type std::shared_ptr<MyClass>& and std::shared_ptr<MyClass>&& instead of boost::any& and boost::any&& respectively. By expectation, I mean that the output in that case is

lvalue reference
rvalue reference

The question here is why is it not able to distinguish between lvalue and rvalue reference of boost::any type, while it is able to do so for std::shared_ptr?

I went through this answer, which explains 'better matching' for overload resolution, but I'm not quite sure why it is not applying for boost::any, more so given that it is working for std::shared_ptr.

Versions: clang version 3.4.2, boost 1.53, also checked with boost 1.82.


Solution

  • The problem isn't with boost::any but the fact that there is an implicit conversion from std::shared_ptr to boost::any. We get the same effect when passing an integer into a function that accepts a double:

    #include <print>
    
    void f(double&& d) {
        std::println("rvalue reference");
    }
    
    void f(const double& d) {
        std::println("lvalue reference");
    }
    
    
    int main() {
        double d = 1.0;
        f(d);               // lvalue reference
        f(std::move(d));    // rvalue reference
    
        int n = 1;
        f(n);               // rvalue reference
        f(std::move(n));    // rvalue reference
    }