#include <iostream>
#include <string>
//------------------------ Common support:
namespace option {
template< class Name, class ValueType >
class Value
{
template< class N, class V >
friend V const& get( Value< N, V > const& );
template< class N, class V, class A >
friend void set( Value< N, V >&, A const& );
private:
ValueType value_;
public:
Value( ValueType const& v = ValueType() )
: value_( v )
{}
typedef ValueType value_type;
typedef Name name_type;
};
template< typename O, int I>
struct OpLayer : O {
typedef char R[I];
typedef R &Rf(typename O::name_type);
operator Rf*() const;
OpLayer( typename O::value_type const& v = typename O::value_type() )
: O( v )
{}
};
template< class Name, class ValueType >
ValueType const& get(
Value< Name, ValueType > const& option
)
{
return option.value_;
}
template< class Name, class ValueType, class ActualArgType >
void set(
Value< Name, ValueType >& option,
ActualArgType const& v
)
{
option.value_ = v;
}
struct none {
typedef none value_type;
typedef none *name_type;
};
template<typename O1 = none, typename O2 = none,
typename O3 = none, typename O4 = none,
typename O5 = none>
struct OptionList
:
OpLayer<O1, 1>,
OpLayer<O2, 2>,
OpLayer<O3, 3>,
OpLayer<O4, 4>,
OpLayer<O5, 5>
{
template<int N, typename = void>
struct index;
template<typename V> struct index<1, V> {
typedef typename O1::value_type value_type;
};
template<typename V> struct index<2, V> {
typedef typename O2::value_type value_type;
};
template<typename V> struct index<3, V> {
typedef typename O3::value_type value_type;
};
template<typename V> struct index<4, V> {
typedef typename O4::value_type value_type;
};
template<typename V> struct index<5, V> {
typedef typename O5::value_type value_type;
};
template<typename Name>
struct name2val {
typedef typename index<sizeof (*(OptionList*)0) (*(Name*)0)>::value_type type;
};
template< class Name >
typename name2val<Name>::type const& get() const {
return option::get<Name>(*this);
}
};
} // namespace option
//------------------------ A particular options class & test program:
namespace name {
typedef struct width_namestruct* width;
typedef struct height_namestruct* height;
typedef struct title_namestruct* title;
} // namespace name
struct Options
: option::OptionList<
option::Value< name::width, int>,
option::Value< name::height, int>,
option::Value< name::title, std::string> >
{
public:
template< class Name, class ActualArgType >
Options& with( ActualArgType const& v )
{
option::set<Name>( *this, v );
return *this;
}
};
int main()
{
using namespace std;
using namespace name;
using namespace option;
Options const o = Options()
.with<width>( 82 )
.with<height>( 19 )
.with<title>( "My button" );
cout << "Width = " << o.get<width>() << endl;
cout << "Height = " << o.get<height>() << endl;
cout << "Title = \"" << o.get<title>() << "\"" << endl;
}