Неоднозначные аргументы шаблона не исключаются с помощью enable_if - PullRequest
3 голосов
/ 15 марта 2012

Я хочу автоматически выбрать правильный указатель на член среди перегруженных на основе «типа» члена, удалив специализации, которые принимают неравнодушных членов (через enable_if).

У меня есть следующеекод:

class test;

enum Type
{
    INT_1,
    FLOAT_1,
    UINT_1,
    CHAR_1,
    BOOL_1,
    INT_2,
    FLOAT_2,
    UINT_2,
    CHAR_2,
    BOOL_2
};
template<typename T, Type Et, typename func> struct SetterOk                            { static const bool value = false; };
template<typename T> struct SetterOk<T,INT_1,void (T::*)(int)>                          { static const bool value = true; };
template<typename T> struct SetterOk<T,FLOAT_1,void (T::*)(float)>                      { static const bool value = true; };
template<typename T> struct SetterOk<T,UINT_1,void (T::*)(unsigned int)>                { static const bool value = true; };
template<typename T> struct SetterOk<T,CHAR_1,void (T::*)(char)>                        { static const bool value = true; };
template<typename T> struct SetterOk<T,BOOL_1,void (T::*)(bool)>                        { static const bool value = true; };
template<typename T> struct SetterOk<T,INT_2,void (T::*)(int,int)>                      { static const bool value = true; };
template<typename T> struct SetterOk<T,FLOAT_2,void (T::*)(float,float)>                { static const bool value = true; };
template<typename T> struct SetterOk<T,UINT_2,void (T::*)(unsigned int, unsigned int)>  { static const bool value = true; };
template<typename T> struct SetterOk<T,CHAR_2,void (T::*)(char,char)>                   { static const bool value = true; };
template<typename T> struct SetterOk<T,BOOL_2,void (T::*)(bool,bool)>                   { static const bool value = true; };

template <bool, class T = void> struct enable_if {};
template <class T> struct enable_if<true, T> { typedef T type; };


template<typename T, Type Et>
struct Helper
{
    template<typename U>
    static void func(U method, typename enable_if<SetterOk<T,Et,U>::value>::type* dummy = 0)
    {
    }
};

class test
{
    public:
        void init()
        {
            Helper<test,INT_2>::func(&test::set);
        }

        void set2(int);
        void set(int);
        void set(int,int);
        void set(float,float);
};

int main()
{
    test t;
    t.init();
    return 0;
}

Я ожидаю, что он выберет правильную функцию из всех возможных.Проблема в том, что компилятор говорит «не может вывести аргумент шаблона, так как аргумент функции неоднозначен».

Кажется, я не знаю, как использовать enable_if, потому что в этом случае компилятор разрешит специализацию, только если указанныйФункция имеет правильный тип ...

Обратите внимание, что я хочу иметь решения C ++ 03 (если возможно) - мой код должен компилироваться на некоторых старых компиляторах.

Заранее спасибо

Ответы [ 2 ]

1 голос
/ 15 марта 2012

Причина, по которой он не компилируется, заключается в том, что есть несколько различных перегруженных функций, и он не знает, какую именно вы имеете в виду. Конечно, только один из них (void set (int, int)) будет фактически скомпилирован, учитывая специализацию Helper<test,INT_2>. Однако этого недостаточно для продолжения работы компилятора.

Один из способов получить это для компиляции - явное приведение &test::set к соответствующему типу:

Helper<test,INT_2>::func(static_cast<void (test::*)(int,int)>(&test::set));

Другой способ - использовать явную специализацию шаблона:

Helper<test,INT_2>::func<void (test::*)(int,int)>((&test::set));

В любом случае, вы должны сообщить компилятору, к какой из функций набора вы обращаетесь.

EDIT:

Насколько я понимаю, вы хотите, чтобы из использования Type можно было определить, какой тип функции следует использовать. Следующая альтернатива достигает этого:

template<typename T, Type Et> struct SetterOK{};
template<typename T> struct SetterOK<T,INT_1> {typedef void (T::*setter_type)(int);};
template<typename T> struct SetterOK<T,FLOAT_1> {typedef void (T::*setter_type) (float);};
// ...
template<typename T> struct SetterOK<T,INT_2> {typedef void (T::*setter_type)(int,int);};
// ....

template<typename T, Type Et>
struct Helper
{
  template<typename U>
  static void func(U method)
  {
  }
};

class test
{
public:
  void init()
  {
    Helper<test,INT_2>::func<SetterOK<test,INT_2>::setter_type >(&test::set);
  }

  void set2(int);
  void set(int);
  void set(int,int);
  void set(float,float);
};

int main()
{
  test t;
  t.init();
  return 0;
}

ДОПОЛНИТЕЛЬНОЕ РЕДАКТИРОВАНИЕ:

Мысль только что пришла мне в голову. В этом специальном случае, который вы сделали, где U - SetterOK :: setter_type, можно еще больше упростить ситуацию, полностью удалив аргументы шаблона для func:

static void func(typename SetterOK<T,Et>::setter_type method)
{
}

Это сделает метод init более простым:

void init()
{
  Helper<test,INT_2>::func(&test::set);
}
1 голос
/ 15 марта 2012

Вы никогда не можете ссылаться на перегруженную функцию, не устраняя ее неоднозначность (означает: static_cast с правильным типом).Когда вы создаете экземпляр Helper::func, тип аргумента функции не может быть известен без его устранения неоднозначности.

...