Реальная проблема в том, что вам нужно решение на C ++ 03, поэтому вы можете использовать SFINAE, но не все улучшения языка, доступные начиная с C ++ 11.
В любом случае, я предлагаю вам решениеэто извилистое, как у вас (может быть, больше), но совершенно бесплатное повышение.
Если вы определяете тривиальную оболочку bool (которая может примерно заменить C ++ 11 std::true_type
и std::false_type
)
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>
{ };
и если вы определите черты типа enable_if
(такие же, как в C ++ 11 std::enable_if
)
template <bool, typename = void>
struct enable_if
{ };
template <typename T>
struct enable_if<true, T>
{ typedef T type; };
вы можете SFINAE включить / отключить ваши foo()
функции
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"; }
Ниже приведен полностью рабочий пример C ++ 98
#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
}
Я не знаю повышенияклассы, которыми вы пользуетесь, но я полагаю, что вы можете изменить свой код (чтобы он работал почти как мое решение без буста) следующим образом
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>
{ };
- РЕДАКТИРОВАТЬ -
ОП спрашивают
Я не понимаю, как это работает для случая A1 <0>.Специализация Condition должна быть предпочтительным совпадением, со вторым аргументом, расширяющимся до bool_.Этот класс наследуется от bool_, поэтому он должен выбирать неправильные версии foo.Однако это работает.Как это возможно?
Хорошо ... когда вы пишете foo(A1<0>())
, компилятор должен понимать, является ли cond<A1<0>>::value
true
или false
для включения первой версии foo()
или второй.
Таким образом, компилятор должен реализовать cond<A1<0>>
.Но нет шаблона класса cond
, который получает только имя типа.В любом случае, компилятор обнаружил, что
template <typename, typename = bool_wrapper<true> >
struct cond;
совпадает с использованием значения по умолчанию для второго параметра шаблона.
Альтернативы нет, поэтому двусмысленности нет, поэтому cond< A<1> >
становитсяcond< A<1>, bool_wrapper<true> >
Теперь компилятор должен выбирать между основной версией cond<typename, typename>
(той, которая наследуется от bool_wrapper<false>
) и специализацией (той, которая наследуется от bool_wrapper<true>
).
cond< A<1>, bool_wrapper<true> >
точно соответствует основной версии, но соответствует также специализации?Если совпадает также со специализацией, компилятор должен предпочесть специализацию.
Так что нам нужно посмотреть, соответствует ли cond< A<0>, bool_wrapper<true> >
специализации.
Используя A<0>
как T
, мы имеемчто специализация становится
cond< A<0>, bool_wrapper<(1 == A<0>::code) || (2 == A<0>::code)> >
, то есть
cond< A<0>, bool_wrapper<(1 == 0) || (2 == 0)> >
, то есть
cond< A<0>, bool_wrapper<false || false> >
, то есть
cond< A<0>, bool_wrapper<false> >
, и это не 't соответствует cond< A<0>, bool_wrapper<true> >
.
Так что cond< A<0> >
, то есть cond< A<0>, bool_wrapper<true> >
, соответствует только основной версии cond<typename, typename>
, поэтому наследуем от bool_wrapper<false>
.
Теперь мы можем датьcond< A<1> >
.
Что касается cond< A<0> >
, единственный шаблон cond
, который соответствует cond< A<1> >
, это cond<typename, typename>
со вторым typename
со значением по умолчанию.
Итак cond< A<1> >
- это cond< A<1>, bool_wrapper<true> >
.
Но cond< A<1>, bool_wrapper<true> >
соответствует только основной версии cond<typename, typename>
или также специализации?
Мы можем видеть, что A<1>
используется как T
, у нас есть специализация:
cond< A<1>, bool_wrapper<(1 == A<1>::code) || (2 == A<1>::code)> >
, то есть
cond< A<1>, bool_wrapper<(1 == 1) || (2 == 1)> >
, то есть
cond< A<1>, bool_wrapper<true || false> >
, то есть
cond< A<1>, bool_wrapper<true> >
и это соответствует cond< A<1>, bool_wrapper<true> >
.
Итак, дляcond< A<1> >
, AKA cond< A<1>, bool_wrapper<true>
, обе версии cond<typename, typename>
совпадают, поэтому компилятор должен выбрать специализацию, поэтому cond< A<1> >
наследуется от bool_wrapper<true>
.