Boost logo

Boost Users :

Subject: Re: [Boost-users] Constraining unordered template constructors
From: Jeffrey Lee Hellrung, Jr. (jeffrey.hellrung_at_[hidden])
Date: 2013-05-15 01:30:26


On Sat, May 11, 2013 at 9:37 PM, Michael Marcin <mike.marcin_at_[hidden]>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



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net