Эквивалентность typedef в аргументах функции - PullRequest
4 голосов
/ 18 января 2011

Вопрос довольно трудно задать без примера, поэтому вот он:

#include <vector>

struct O
{
};

struct C
{
  template <typename T>
  void function1(void (C::*callback)(const O*));

  template <typename T>
  void function2(void (C::*callback)(const typename T::value_type));

  void print(const O*);
};


int main()
{
  C c;

  c.function1< std::vector<O*> >(&C::print); // Success.
  c.function2< std::vector<O*> >(&C::print); // Fail.
}

Ошибка, которую мне дают:

error: no matching function for call to ‘C::function2(void (C::*)(const O*))’.

По сути, единственное различие между вызовами состоит в том, что в function2 я более универсален, поскольку использую typedef std::vector<O*>::value_type, который должен преобразовываться в O*, следовательно, похож на function1.

Я использую G ++ 4.2.1 (я знаю, что он старый), но Comeau подтверждает, что я неправ.

Почему компиляция не удалась?

1 Ответ

4 голосов
/ 18 января 2011

Ваша проблема в том, что const typename T::value_type в основном typename T::value_type const, который разрешается в O* const, что, очевидно, не то же самое, что const O* (что будет O const *, при написании объявления ptr после типа (более полезновыяснить это поведение)).

Что касается архивирования того, что вы хотите, то все зависит от того, что вы хотите.Если вы хотите использовать boost type_traits или tr1 type_traits, чтобы убрать указатель, добавьте const и снова сделайте его указателем, например:

template <typename T>
void function2(void (C::*callback)(typename boost::add_pointer<typename boost::add_const<typename boost::remove_pointer<typename T::value_type>::type>::type>::type));

Использование tr1 вместо boost должно бытьвопрос замены boost:: на std::tr1::.

Однако я бы точно не назвал это полезным обобщением, поэтому вы можете подумать, если действительно хотите пойти по этому пути.Лично я бы использовал что-то вроде boost function или свободные функции в качестве обратных вызовов, первый из которых обеспечивает гораздо большую гибкость в том, что можно использовать в качестве обратных вызовов (бесплатные функции, функторы, функции-члены), а последний, по крайней мере, облегчает созданиевторая функция, которая будет соответствующим образом преобразовывать аргументы (то есть, если вы хотите использовать функцию, которая получает const O* в качестве параметра, вы можете создать такую, которая принимает O* и вызывает первую функцию с этим параметром, и использует эту функцию в качестве обратного вызова).

...