Re: How can I use unqualified names? (Possibly hard or impossible?)
* Alf P. Steinbach:
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!
First, thanks to Jonathan Lee (else-thread) for a different tack on the option
pack problem, the problem that led to the above. Yeah, I'm using that and'ing
scheme for simpler options, those that are encoded as bit-fields. But I don't
quite see how it helps with the above.
Anyway, I found a sort of almost-solution, shown below.
It doesn't get rid of qualification as I wanted, but it reduces qualification to
only one qualifier, which can be freely named within a usage class.
It's sort of like if one could have 'using namespace foo=' within a class. :-)
Might be a useful technique on its own.
<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>
namespace blahblah {
namespace reallyLongName {
namespace california {
namespace pos2 {
typedef OptionsMember_<double, struct UniqueTypeFor_x> x;
typedef OptionsMember_<double, struct UniqueTypeFor_y> y;
typedef Options_< WithMembers_<x, y> > Options;
struct Names
{
typedef pos2::Options Options;
typedef pos2::x x;
typedef pos2::y y;
};
}}}} // namespace blahblah::reallyLongName::california::pos2
struct UserClass1
{
//using namespace pos2 = blahblah::reallyLongName::california::pos2;
typedef ::blahblah::reallyLongName::california::pos2::Names pos2;
UserClass1( pos2::Options const& options )
{
using namespace std;
cout << options.pos2::x::member << endl;
cout << options.pos2::y::member << endl;
}
};
namespace blahblah {
namespace reallyLongName {
namespace california {
namespace pos3 {
typedef OptionsMember_<double, struct UniqueTypeFor_z> z;
typedef Options_< WithMembers_<pos2::Options, z> > Options;
struct Names: pos2::Names
{
typedef pos3::Options Options;
typedef pos3::z z;
};
}}}} // namespace blahblah::reallyLongName::california::pos3
struct UserClass2: UserClass1
{
//using namespace pos3 = blahblah::reallyLongName::california::pos3;
typedef ::blahblah::reallyLongName::california::pos3::Names pos3;
UserClass2( pos3::Options const& options )
: UserClass1( options )
{
using namespace std;
cout << std::endl;
cout << options.pos3::x::member << endl;
cout << options.pos3::y::member << endl;
cout << options.pos3::z::member << endl;
}
};
int main()
{
//using namespace pos3 = blahblah::reallyLongName::california::pos3;
typedef UserClass2::pos3 pos3;
UserClass2( pos3::Options() << pos3::x(3.14) << pos3::z(42) );
}
</code>
Now, if I could just see some way to use e.g. macros to make the option pack
definitions less verbose & more readable...
Cheers,
- Alf