On Sat, May 11, 2013 at 9:37 PM, Michael Marcin <mike.marcin@gmail.com> wrote:
I have a class that I want to have accept 0-5 arguments in any order for it's constructor. Each argument is a const references to one of 5 possible class types. All arguments must be distinct in type, passing the same type twice in an error. Passing an argument that is not one of the 5 supported types is also an error.

How do you go about implementing something like this?

I figure first you have to create a constructor for each arity but then how do you constrain the constructors as described above? I imagine it would involve enable_if.

class widget
{
  widget();

  template< class A >
  widget( const A& a );

  template< class A, class B >
  widget( const A& a, const B& b );

  template< class A, class B, class C >
  widget( const A& a, const B& b, const C& c );

  template< class A, class B, class C, class D >
  widget( const A& a, const B& b, const C& c, const D& d );

  template< class A, class B, class C, class D, class E >
  widget( const A& a, const B& b, const C& c, const D& d, const E& e );
};

To strictly address the problem above:

First, decide if you really need to constrain the constructor signatures, or if it's sufficient to just static_assert on misuse. If you really need the former, you can make it work with enable_if.

Now, determining whether the template binding is "valid" (as defined above)? I can't think of a super simple way to do this. But there is a way; I'm thinking of using Boost.MPL. Something like:

typedef mpl::set< /*fill in your 5 types here*/ > my_types;

template< class I, class End, class Seen >
struct is_valid_iterate
  : mpl::eval_if_c<
      mpl::contains< my_types, typename mpl::deref<I>::type >::value &&
      !mpl::contains< Seen, typename mpl::deref<I>::type >::value,
      is_valid_iterate<
        typename mpl::next<I>::type, End,
        typename mpl::push_back< Seen, typename mpl::deref<I>::type >::type
      >,
      mpl::false_
    >
{ };

template< class End, class Seen >
struct is_valid_iterate : mpl::true_ { };

template< class V >
struct is_valid
  : is_valid_iterate<
      typename mpl::begin<V>::type,
      typename mpl::end<V>::type,
      mpl::set0<>
    >
{ };

Now, I'm not sure if there's an mpl::contains, but it would be easy enough to write; and you can probably shorten this a bit by only typing out mpl::deref<I>::type once; but that's the basic idea to one approach. This is entirely just a sketch so there might be some incorrect details but hopefully it conveys the idea.

Now, whether the original problem you posed is *really* the problem you want to solve is another story... :)

HTH,

- Jeff