Boost logo

Boost :

From: David B. Held (dheld_at_[hidden])
Date: 2002-07-09 14:03:00


"Giovanni Bajo" <giovannibajo_at_[hidden]> wrote in message
news:048c01c22772$ac3d78e0$7a4e2a97_at_bagio...
> [...]
> I believe that you're still missing my main point against the need of a
> operator->*

No, I got that; but I disagree that it's always better to use bind(). For
instance, on bcc, bind() just got confused about my pointer-to-member
type (probably due to Borland's __closure extension). So I had to go
back to shared_ptr::get().

> (which I still agree it could be added, but I think it's basically
useless).
> The point is that you shouldn't want an operator->* in shared_ptr in
> the first place, becuase you shouldn't be using (as in: storing) a
> pointer-to-member-function in the first place.

Who says I'm storing one? ;)

> Boost (bind+function) provides very powerful, elegant, and more
> generic alternatives, that do not require overloading of ->* at all.

Yes. It provides an alternative syntax. And bind+function is very
powerful, no doubt about that.

> [...]
> Now, I might well be wrong, but I'd like to see a real-word example
> of a codebase that can't be converted to such code (which also
> gives some structural advantages).
> [...]

Well, I certainly don't think it's possible to show code where it is
not possible to use bind+function (except for cases of compiler
confusion, of course). But let me show you my example, and why
I'm using pointer-to-member without boost::function. I can still use
boost::bind, certainly, but operator->* seems more natural in this
case.

This is a template wrapper for BCB's VCL wrapper of the
Windows Registry API. ;) I could have done a lot of things differently.
For instance, originally, I had a different class for each type.
However, that results in a lot of code duplication, and makes
maintenance a nightmare. Converting it to a template-based solution
turned out to be extremely elegant, and reduced the code size by
about a factor of four. TRegistry is the VCL class that does the
hard work of interfacing with the Registry.

Option.h
/////////////////////////////////////////
//--------------------------------------------------------------------------
-
#ifndef OptionH
#define OptionH
//--------------------------------------------------------------------------
-
#include <Registry.hpp>

#include <boost/smart_ptr.hpp>

#include <cassert>
//--------------------------------------------------------------------------
-
namespace CL
{

//-----------------------------------------------------------------------
    typedef boost::shared_ptr<TRegistry> PRegistry;

//-----------------------------------------------------------------------
    // TOptionRegistry

//-----------------------------------------------------------------------
    class TOptionRegistry
    {
    public: // Structors
                        TOptionRegistry(AnsiString const& Application);

        PRegistry Registry(void) const { return Registry_; }
    private: // Implementation
        PRegistry Registry_;
    };

//-----------------------------------------------------------------------
    // TOptionBase

//-----------------------------------------------------------------------
    // I don't think I can use boost::function here because it will miss
    // the __fastcall decoration which is part of how these functions
    // are declared.
    template <typename T,
        T (__fastcall TRegistry::*ReadValue)(AnsiString const),
        void (__fastcall TRegistry::*WriteValue)(AnsiString const, T)>
    class TOptionBase
    {
    public: // Structors
                        TOptionBase(TOptionRegistry const& OptionRegistry,
                            AnsiString const& Name, T const& Default)
                            : Registry_(OptionRegistry.Registry()),
Name_(Name)
        {
            if (Registry_->ValueExists(Name_))
            {
                Read();
            }
            else
            {
                Write(Default);
            }
        }
                       ~TOptionBase(void) { Write(Value_); }
    public: // Methods
        T const& Value(void) const { return Value_; }
        void Value(T const& Value) { Value_ = Value; }

        T const& Read(void)
        {
            return Value_ = (Registry_.get()->*ReadValue)(Name_);
            // Now, I could just as easily call:
            // return Value_ = boost::bind(ReadValue, Registry_)(Name_);
            // Except I don't think that's quite as readable, personally,
            // and unfortunately, bcc doesn't like it.
        }
        void Write(T const& Value)
        {
            (Registry_.get()->*WriteValue)(Name_, Value_ = Value);
        }

                        operator T const&(void) const
                                                { return Value_; }
        TOptionBase& operator =(T const& Value)
                                                { Value_ = Value; return
*this; }
    private: // Implementation
        PRegistry Registry_;
        AnsiString Name_;
        T Value_;
    };

//-----------------------------------------------------------------------
    // TOption

//-----------------------------------------------------------------------
    template <typename T>
    class TOption;

//-----------------------------------------------------------------------
#define CL_OPTION(T, ReadValue, WriteValue)
\
    template <>
\
    class TOption<T>
\

{ \
    public:
\
        typedef TOptionBase<
\
            T, &TRegistry::ReadValue, &TRegistry::WriteValue
\
> Type;
\
    };

//-----------------------------------------------------------------------
    CL_OPTION(bool, ReadBool, WriteBool);
    CL_OPTION(int, ReadInteger, WriteInteger);
    CL_OPTION(double, ReadFloat, WriteFloat);
    CL_OPTION(AnsiString, ReadString, WriteString);

//-----------------------------------------------------------------------
    typedef TOption<bool>::Type TOptionBool;
    typedef TOption<int>::Type TOptionInt;
    typedef TOption<double>::Type TOptionFloat;
    typedef TOption<AnsiString>::Type TOptionString;

//-----------------------------------------------------------------------
} // namespace CL
//--------------------------------------------------------------------------
-
#endif

//--------------------------------------------------------------------------
-
#include <vcl.h>
#pragma hdrstop

Option.cpp
/////////////////////////////////////////
#include "Option.h"
//--------------------------------------------------------------------------
-
#pragma package(smart_init)
//--------------------------------------------------------------------------
-
namespace CL
{

//-----------------------------------------------------------------------
    AnsiString const
        BaseKey = "Software",
        Company = "Acme ;>";

//-----------------------------------------------------------------------
    // TOptionRegistry

//-----------------------------------------------------------------------
    TOptionRegistry::TOptionRegistry(AnsiString const& Application)
        : Registry_(new TRegistry)
    {
        AnsiString Key = BaseKey + "\\" + Company + "\\" + Application +
"\\Options";
        if (!Registry_->OpenKey(Key, true))
        {
            throw Exception("Unable to open registry key");
        }
    }

//-----------------------------------------------------------------------
} // namespace CL
//--------------------------------------------------------------------------
-

Dave


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