|
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