enable_if and constructors
I see examples of enable_if used to specify a return type to a function:
template <class T>
typename enable_if_c
Angus Leeming wrote:
Even if this turns out to be impossible, I'd like to go on and try to define some_boolean_condition if I may. I see that Aleksey plans a contains_c metafunction for 1.33,
Apologies for replying to self, but I have managed to define a contains_c metafunction. (Below). I still don't know how to use it with enable_if, however. This fails to compile: boost::enable_if< mpl::contains_c< mpl::vector_c< int, foo::state2, foo::state3 > , foo::state2 > , foo::state
::type s = foo::state2;
My naïve understanding is that enable_if<...>::type should be foo::state
here. Any pointers?
Regards,
Angus
#include
Angus Leeming
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.
Well, you can do something like:
template <class N>
foo(
N
, typename boost::enable_if<
typename contains_c<
mpl::vector_c >::type
, typename mpl::end<S>::type
>
>
{};
and then a foo is constructed something like this:
foo x( mpl::int_<state2>() );
HTH,
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com
David Abrahams wrote:
Angus Leeming
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::setfoo::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::setfoo::state2() { return foo::state2; }
template <>
foo foo::setfoo::state3() { return foo::state3; }
int main()
{
// Compiles, as expected.
foo f1 = foo::setfoo::state2();
foo f2(foo::setfoo::state2());
// Fail to compile, as expected.
// foo f3 = foo::setfoo::state1();
// foo f4(foo::setfoo::state1());
return 0;
}
Regards,
Angus
-----------------------------------------------------------------------
My version of Dave Abrahams's working version of my broken original ;-)
#include
>
>::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
Angus Leeming
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; }
Without a definition for invalid_value, this is invalid code, and on a conforming compiler, compilation fails at the point it is parsed.
private: foo(state) { std::cout << "foo" << std::endl; } };
template <> foo foo::setfoo::state2() { return foo::state2; }
template <> foo foo::setfoo::state3() { return foo::state3; }
int main() { // Compiles, as expected. foo f1 = foo::setfoo::state2(); foo f2(foo::setfoo::state2()); // Fail to compile, as expected. // foo f3 = foo::setfoo::state1(); // foo f4(foo::setfoo::state1());
return 0; }
-- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams wrote:
// Only the specializations (below) of this template will compile. template <int N> static foo set() { return invalid_value; }
Without a definition for invalid_value, this is invalid code, and on a conforming compiler, compilation fails at the point it is parsed.
Thanks again. g++ 3.3 appears to happy differentiate between "valid" and
"invalid" enum values with the code below, so allow me to rephrase my
earlier question: which of the two techniques we've discussed would you
use? I assume that one has technical merits over the other?
Regards,
Angus
#include
Angus Leeming
David Abrahams wrote:
// Only the specializations (below) of this template will compile. template <int N> static foo set() { return invalid_value; }
Without a definition for invalid_value, this is invalid code, and on a conforming compiler, compilation fails at the point it is parsed.
Thanks again. g++ 3.3 appears to happy differentiate between "valid" and "invalid" enum values with the code below,
Well *that* code is valid, unlike the code of your previous post.
so allow me to rephrase my earlier question: which of the two techniques we've discussed would you use?
I have no opinion.
I assume that one has technical merits over the other?
I don't know; they're both pretty ugly ;-) -- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (2)
-
Angus Leeming
-
David Abrahams