Boost logo

Boost Users :

From: Angus Leeming (angus.leeming_at_[hidden])
Date: 2005-04-05 10:31:15


David Abrahams wrote:

> Angus Leeming <angus.leeming_at_[hidden]> writes:
>
>> Is it possible to use enable_if with a constructor?
>
> In principle, yes. You just add a dummy default parameter for the
> enabler.
>
>> For example, I'd like to define a constructor that allows only
>> certain values of an enum:
>
> No chance; that's a runtime test... or you'd have to specify the enum
> as a template argument to the ctor explicitly... but you can't provide
> explicit template arguments to ctors.

Many, many thanks, Dave, both for the explanations and for the working
code.

Your code worked perfectly of course, but I decided to use a static "set"
member function to return a foo instance:
    foo x(foo::set<foo::state2>());

I guess that this is semantically equivalent to your
    foo x(mpl::int_<foo::state2>());

FWIW, I include my working version of this MPL code at the bottom of this
mail. However, it all seems like a lot of machinery. In my case, there are
only a few "valid" enum values. What are the advantages of the Boost.MPL
approach over the functionally identical:

#include <iostream>

class foo {
public:
    enum state {
        state1,
        state2,
        state3
    };

    // Only the specializations (below) of this template will compile.
    template <int N>
    static foo
    set() { return invalid_value; }

private:
    foo(state)
    {
        std::cout << "foo" << std::endl;
    }
};

template <>
foo foo::set<foo::state2>() { return foo::state2; }

template <>
foo foo::set<foo::state3>() { return foo::state3; }

int main()
{
    // Compiles, as expected.
    foo f1 = foo::set<foo::state2>();
    foo f2(foo::set<foo::state2>());
    // Fail to compile, as expected.
// foo f3 = foo::set<foo::state1>();
// foo f4(foo::set<foo::state1>());

    return 0;
}

Regards,
Angus

-----------------------------------------------------------------------
My version of Dave Abrahams's working version of my broken original ;-)

#include <boost/type_traits/is_integral.hpp>

#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/mpl/end.hpp>
#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/find_if.hpp>
#include <boost/mpl/lambda.hpp>
#include <boost/mpl/integral_c.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/vector_c.hpp>

#include <iostream>

namespace boost {
namespace mpl {

template <class S, int N>
  struct contains_c
    : not_<
          is_same<
              typename find_if<S,
                  equal_to<_1,
                      integral_c<typename S::value_type, N>
>
>::type
            , typename end<S>::type
>
>
  {};

} // namespace boost
} // namespace mpl

class foo {
public:
    enum state {
        state1,
        state2,
        state3
    };

    // Will compile only for state2 and state3
    template <int N>
    static
    typename boost::enable_if<
        typename boost::mpl::contains_c<
            boost::mpl::vector_c<int, state2, state3>
          , N
>
      , foo
>::type
    set() { return foo(static_cast<state>(N)); }

private:
    foo(state)
    {
        std::cout << "foo" << std::endl;
    }
};

int main()
{
    // Compiles, as expected.
    foo f1 = foo::set<foo::state2>();
    foo f2(foo::set<foo::state2>());
    // Fail to compile, as expected.
// foo f3 = foo::set<foo::state1>();
// foo f4(foo::set<foo::state1>());

    return 0;
}


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