Boost::any reference to stored value not compiling

928 views Asked by At

I'm trying to write a generic configuration class that holds parameters like this (simplified greatly):

class Parameter
{
public:
   Parameter(boost::any value, bool isRequired) 
     : value(value), isRequired(isRequired) {}
   bool isSet;
   bool isRequired;
   boost::any value;
};

class ParameterGroup
{
public:
   map<std::string, Parameter> table;
   // references for chaining
   ParameterGroup& add_parameter_group(const string &token, const bool isRequired);
   ParameterGroup& add_parameter(const string &token, const bool isRequired);

   template<typename T>
   T& get_parameter(const string &token);
};

The problem is in the add_parameter_group function:

ParameterGroup& ParameterGroup::add_parameter_group(const string &token, 
                                                    const bool &isRequired)
{
   table[token] = Parameter(ParameterGroup(), isRequired);
   return boost::any_cast<ParameterGroup>(table[token].value);
}

The return fails to compile with the message

error: invalid initialization of non-const reference of type ParameterGroup& from an 
       rvalue of type ParameterGroup

I don't see why. According to the boost::any_cast documentation:

If passed a pointer, it returns a similarly qualified pointer to the value content if successful, otherwise null is returned. If T is ValueType, it returns a copy of the held value, otherwise, if T is a reference to (possibly const qualified) ValueType, it returns a reference to the held value.

Why is this failing to return a reference as it seems it should?

2

There are 2 answers

3
Lightness Races in Orbit On BEST ANSWER

T is not a reference type, but ValueType, so according to the documentation you quoted, you get a value.

You are then trying to bind this [temporary] value to a ref-to-non-const.

The clause you are trying to activate is:

if T is a reference to (possibly const qualified) ValueType, it returns a reference to the held value.

So, let's make T a reference to ValueType:

boost::any_cast<ParameterGroup&>(table[token].value);
//              ^^^^^^^^^^^^^^^
//              |------------||
//                ValueType (ref)
//              |-------------|
//                     T

Now you'll get a reference to the held value, which'll bind just fine to the return type.

1
Davidbrcz On

Directly taken from boost::any header

  template<typename T> T any_cast(any &);
  template<typename T> T any_cast(const any &);
  template<typename ValueType> const ValueType * any_cast(const any *);
  template<typename ValueType> ValueType * any_cast(any *);

So you see that boost::any_cast returns a copy when you ask for a value, that is why you cant return a reference. So try any_cast with casting a reference