Boost logo

Boost :

From: Dan Nuffer (dnuffer_at_[hidden])
Date: 2000-11-03 13:10:45


I think that "any" should be accepted into Boost.

I have spent a few hours reading the paper, documentation, and code.
I also started using it in a compiler I am working on.
Previously I had a class for Tokens that looked something like this
(extraneous details removed):

class Token
{
public:
        Symbol sy;
        union
        {
                std::string id;
                char ch;
                int num;
                float rnum;
        } data;
        
        Token( Token& other )
        {
                switch ( sy )
                {
                case identsy:
                        data.id = other.data.id;
                        break;
 
                case charconsy:
                        data.ch = other.data.ch;
                        break;
                case intconsy:
                        data.num = other.data.num;
                        break;
                case realconsy:
                        data.rnum = other.data.rnum;
                        break;

                case stringsy:
                        data.id = other.data.id;
                        break;
                }
        };
};

Depending on what the value of Token.sy was, a value from Token.data was
used at various places in the compiler.
This was not very safe (e.g. if a Token was initialized as an integer
and then the code mistanely accessed Token.data.id == *bug*). The copy
constructor was just plain ugly.

Using any I was able to simplify it to the following:
class Token
{
private:
        Symbol sy;

        any data;

public:
        Symbol getSymbol()
                { return sy; }

        Identifier getIdentifier( ) const
                { return any_cast<Identifier>(data); }
        void setIdentifier( const Identifier& i )
                { data = i; }

        CharLiteral getCharLiteral( ) const
                { return any_cast<CharLiteral>(data); }
        void setCharLiteral( const CharLiteral& c )
                { data = c; }

        ... more getters and setters for other Literal types.
};

This is now safer. If the code mistakenly gets the wrong type, then an
exception will be thrown and the program can be easily debugged, which
is better than the random behavior I would've had with the earlier
version. I also could remove the ugly copy constructor because the
compiler generated one will have the correct behavior.

Code:
I found the MSVC_INCLUDE/MSVC_EXCLUDE macros making the code harder to
understand. I find it easier to read things like this:

#ifdef MSVC_BUG
        msvc code
#else
        normal code
#endif

Also, I am using gcc 2.95.2 on Caldera OpenLinux 2.4
and any_cast wouldn't compile.
gcc was giving the following warning:

src/tokenizer/any.hpp:179: parse error before `>'

It didn't like the to_ptr<ValueType> for some strange reason. It
normally accepts this syntax...
To get around the problem I had to add a little template helper:

  template <typename ValueType>
  const ValueType * to_ptr_helper( ValueType* ) const
  {
    return const_cast<any *>(this)->to_ptr<ValueType>();
  }

and then change any_cast to this:

    template<typename ValueType>
    ValueType any_cast(const any & operand)
    {
        ValueType* dummy;
        const ValueType * result =
            operand.to_ptr_helper(dummy);

        if(!result)
        {
            throw bad_any_cast();
        }

        return *result;
    }

--Dan Nuffer


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk