How can I use unqualified names? (Possibly hard or impossible?)
Original problem: a pack of options that may contain a great many simple
numerical and bitset options (defined by external API), and that should be (1)
extensible for at least two levels, like class derivation, (2) easy to define,
(3) easily constructible specifying only those options of interest, defaulting
on the rest, (4) clean notation for accessing options, with compile time
checking, and (5) if possible as efficient as possible access of options.
My silly idea: represent option names as types, and support creation notation like
Options() << x(42) << alpha(3.14)
where 'x' and 'alpha' and other option names are type names. This allows compile
time access of options via notation like 'options::x.member' or e.g.
'options.member<x>', with efficiency as for ordinary member access. Defining a
set of options is reasonably simple, given a little template-based support.
Problem: long qualified option names are impractical and unreadable, but short
good names like 'x' can easily conflict with client code. Especially where that
client code cretating an Options instance is a constructor initializer list a
'using namespace...' isn't practical (as far as I can see, but I may be wrong).
I started thinking in terms of ADL and such, but no dice: my brain cannot come
up with good solution, even now after having slept on it!
Any help appreciated.
Test-of-concept-code, although perhaps best ignored since it constitutes the box
that I'm unable to break out of (I'm not using typelists cause this is just
testing, and also because that would possibly complicate usage):
<code>
template< typename OptionValues >
class Options_: public OptionValues
{
public:
template< typename OptionType >
Options_& operator<<( OptionType const& option )
{
//STATIC_ASSERT( IS_DERIVED_AND_BASE( Options_, OptionType ) );
static_cast<OptionType&>(*this) = option;
return *this;
}
template< typename OptionType >
OptionType const& as() const
{
//STATIC_ASSERT( IS_DERIVED_AND_BASE( Options_, OptionType ) );
return static_cast<OptionType const&>( *this );
}
};
template< typename T, typename Unique >
struct OptionsMember_
{
T member;
OptionsMember_(): member() {}
OptionsMember_( T const& aValue ): member( aValue ) {}
operator T& () { return member; }
operator T const& () const { return member; }
};
struct Nix {};
template<
class T,
class U = Nix,
class V = Nix,
class W = Nix,
class X = Nix,
class Y = Nix,
class Z = Nix
>
struct WithMembers_;
template< class T, class U, class V, class W, class X, class Y, class Z >
struct WithMembers_: T, U, V, W, X, Y, Z {};
template< class T, class U, class V, class W, class X, class Y >
struct WithMembers_<T, U, V, W, X, Y>: T, U, V, W, X, Y {};
template< class T, class U, class V, class W, class X >
struct WithMembers_<T, U, V, W, X>: T, U, V, W, X {};
template< class T, class U, class V, class W >
struct WithMembers_<T, U, V, W>: T, U, V, W {};
template< class T, class U, class V >
struct WithMembers_<T, U, V>: T, U, V {};
template< class T, class U >
struct WithMembers_<T, U>: T, U {};
template< class T >
struct WithMembers_<T>: T {};
//------------------------ Usage:
#include <iostream>
typedef OptionsMember_<double, struct UniqueTypeFor_x> x;
typedef OptionsMember_<double, struct UniqueTypeFor_y> y;
typedef Options_< WithMembers_<x, y> > XYOptions;
void foo( XYOptions const& options )
{
using namespace std;
cout << options.x::member << endl;
cout << options.y::member << endl;
}
typedef OptionsMember_<double, struct UniqueTypeFor_z> z;
typedef Options_< WithMembers_<XYOptions, z> > XYZOptions;
void foo( XYZOptions const& options )
{
using namespace std;
foo( options.as<XYOptions>() );
cout << std::endl;
cout << options.x::member << endl;
cout << options.y::member << endl;
cout << options.z::member << endl;
}
int main()
{
foo( XYZOptions() << x(3.14) << z(42) );
}
</code>
Cheers & TIA for any help,
- Alf