частичная специализация шаблона класса, параметризованная для возвращаемого типа функции-члена - PullRequest
6 голосов
/ 25 февраля 2011

Следующий код, который пытается специализировать шаблон класса 'special' на основе возвращаемого типа типов указателей на функции-члены, приводит к ошибке компиляции с VC9:

template<class F> struct special {};
template<class C> struct special<void(C::*)()> {};
template<class R, class C> struct special<R(C::*)()> {};

struct s {};

int main()
{
  special<void(s::*)()> instance;
  return 0;
}

ошибка C2752: 'special': более одной частичной специализации соответствует списку аргументов шаблона

GCC-4.3.4 принимает тот же код, как показано: http://ideone.com/ekWGgЭто ошибка в VC9, и если да, сохранилась ли эта ошибка в VC10?

Однако я предложил ужасно навязчивый обходной путь (по крайней мере, для этого конкретного случая использования. Более общие решения приветствуются):

#include <boost/function_types/result_type.hpp>
#include <boost/type_traits/is_same.hpp>

template<typename F, typename R>
struct is_result_same :
  boost::is_same<
    typename boost::function_types::result_type<F>::type,
    R
  >
{};

template<class F, bool = is_result_same<F, void>::value>
struct special {};

template<class R, class C> struct special<R(C::*)(), true>  {};
template<class R, class C> struct special<R(C::*)(), false> {};

1 Ответ

3 голосов
/ 25 февраля 2011

Это ошибка.

template <class C> struct special<void(C::*)()>;        // specialization 1
template <class R, class C> struct special<R(C::*)()>;  // specialization 2

Согласно 14.5.4.2, частичное упорядочение этих двух специализаций шаблонов классов такое же, как частичное упорядочение этих шаблонов мнимых функций:

template <class C> void f(special<void(C::*)()>);       // func-template 3
template <class R, class C> void f(special<R(C::*)()>); // func-template 4

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

// Rewrite the function templates with different names -
// template argument deduction does not involve overload resolution.
template <class C> void f3(special<void(C::*)()>);
template <class R, class C> void f4(special<R(C::*)()>);

struct ty5 {}; struct ty6 {}; struct ty7 {};
typedef special<void(ty5::*)()> arg3;
typedef special<ty6 (ty7::*)()> arg4;

  // compiler internally tests whether these are well-formed and
  // the resulting parameter conversion sequences are "exact":
  f3(arg4());
  f4(arg3());

Подробности вывода аргументов шаблона приведены в 14.8.2.Среди действительных вычетов от template_name<dependent_type> и dependent_type1 (dependent_type2::*)(arg_list).Таким образом, вывод f4(arg3()) успешен, вывод f4<void,ty5>(arg3());.Вывод f3(arg4()), очевидно, никогда не может быть успешным, поскольку void и ty6 не объединяются.

Поэтому шаблон функции 3 более специализирован, чем шаблон функции 4. А специализация шаблона класса 1 более специализирована, чем классспециализация шаблона 2. Таким образом, хотя special<void(s::*)()> соответствует обеим специализациям, оно однозначно определяет специализацию 1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...