The real problem is that you need a C++03 solution, so you can use SFINAE but not all language improvement that are available starting from C++11.
Anyway, I propose you a solution that is convoluted like yours (maybe more) but is completely boost free.
If you define a trivial bool wrapper (that can roughly substitute the C++11 std::true_type
and std::false_type
)
template <bool B>
struct bool_wrapper
{ static const bool value = B; };
you can define your condition as follows
template <typename, typename = bool_wrapper<true> >
struct cond : public bool_wrapper<false>
{ };
template <typename T>
struct cond<T, bool_wrapper<(1 == T::code) || (2 == T::code)> >
: public bool_wrapper<true>
{ };
and if you define a enable_if
type traits (the same as the C++11 std::enable_if
)
template <bool, typename = void>
struct enable_if
{ };
template <typename T>
struct enable_if<true, T>
{ typedef T type; };
you can SFINAE enable/disable your foo()
functions
template <typename T>
typename enable_if<false == cond<T>::value>::type foo (T const & arg)
{ std::cout << "no static member code or value not 1 and not 2\n"; }
template <typename T>
typename enable_if<true == cond<T>::value>::type foo (T const & arg)
{ std::cout << "static member code and its value is " << T::code << "\n"; }
The following is a full working C++98 example
#include <iostream>
template <int N> struct A1 { static const int code = N; };
template <int N> struct A2 { static const int code = N; };
// ...
template <int N> struct AN { static const int code = N; };
struct B1{};
struct B2{};
// ...
struct BN{};
template <bool B>
struct bool_wrapper
{ static const bool value = B; };
template <typename, typename = bool_wrapper<true> >
struct cond : public bool_wrapper<false>
{ };
template <typename T>
struct cond<T, bool_wrapper<(1 == T::code) || (2 == T::code)> >
: public bool_wrapper<true>
{ };
template <bool, typename = void>
struct enable_if
{ };
template <typename T>
struct enable_if<true, T>
{ typedef T type; };
template <typename T>
typename enable_if<false == cond<T>::value>::type foo (T const & arg)
{ std::cout << "no static member code or value not 1 and not 2\n"; }
template <typename T>
typename enable_if<true == cond<T>::value>::type foo (T const & arg)
{ std::cout << "static member code and its value is " << T::code << "\n"; }
int main ()
{
foo(A1<0>()); // match the 1st version of foo
foo(A2<1>()); // match the 2nd version of foo
foo(AN<2>()); // match the 2nd version of foo
foo(B1()); // match the 1st version of foo
foo(BN()); // match the 1st version of foo
}
I don't know the boost classes your using but I suppose you can modify your code (to works almost as my no-boost solution) as follows
template <typename, typename = bool_<true> >
struct Condition : public bool_<false>
{ };
template <typename T>
struct Condition<T, bool_<(1 == T::code) || (2 == T::code)> >
: public bool_<true>
{ };
-- EDIT --
The OP ask
I do not understand how it works for the case A1<0>. The specialization of Condition should be the preferred match, with the 2nd argument expanding to bool_. That class inherits from bool_, so, it should pick the wrong versions of foo. However it works. How is it possible?
Well... when you write foo(A1<0>())
, the compiler must understand if cond<A1<0>>::value
is true
or false
to enable the first version of foo()
or the second one.
So the compiler must implement cond<A1<0>>
. But there isn't a cond
template class that receive only a typename. Anyway, the compiler find that
template <typename, typename = bool_wrapper<true> >
struct cond;
matches using the default value for the second template parameter.
There aren't alternative, so there isn't ambiguity, so cond< A<1> >
become cond< A<1>, bool_wrapper<true> >
Now the compiler must choose between the main version of cond<typename, typename>
(the one that inherit from bool_wrapper<false>
) and the specialization (the one that inherit from bool_wrapper<true>
).
cond< A<1>, bool_wrapper<true> >
surely matches the main version, but matches also the specialization? If matches the also the specialization, the compiler must prefer the specialization.
So we need to see if cond< A<0>, bool_wrapper<true> >
matches the specialization.
Using A<0>
as T
, we have that the specialization become
cond< A<0>, bool_wrapper<(1 == A<0>::code) || (2 == A<0>::code)> >
that is
cond< A<0>, bool_wrapper<(1 == 0) || (2 == 0)> >
that is
cond< A<0>, bool_wrapper<false || false> >
that is
cond< A<0>, bool_wrapper<false> >
and this doesn't matches cond< A<0>, bool_wrapper<true> >
.
So cond< A<0> >
, that is cond< A<0>, bool_wrapper<true> >
, matches only the main version of cond<typename, typename>
, so inherit from bool_wrapper<false>
.
Now we can give a look at cond< A<1> >
.
As for cond< A<0> >
, the only template cond
that matches cond< A<1> >
is cond<typename, typename>
with the second typename
with the default value.
So cond< A<1> >
is cond< A<1>, bool_wrapper<true> >
.
But cond< A<1>, bool_wrapper<true> >
matches only the main version of cond<typename, typename>
or also the specialization?
We can see that using A<1>
as T
, we have that the specialization become
cond< A<1>, bool_wrapper<(1 == A<1>::code) || (2 == A<1>::code)> >
that is
cond< A<1>, bool_wrapper<(1 == 1) || (2 == 1)> >
that is
cond< A<1>, bool_wrapper<true || false> >
that is
cond< A<1>, bool_wrapper<true> >
and this matches cond< A<1>, bool_wrapper<true> >
.
So, for cond< A<1> >
, AKA cond< A<1>, bool_wrapper<true>
, both versions of cond<typename, typename>
match, so the compiler must choose the specialization, so cond< A<1> >
inherit from bool_wrapper<true>
.
code
is not a member of theB
classes and It is used in the instantiation ofenable_if
. I have updated the question. – Obryantfoo(B1())
, notfoo(B1{})
– Faux