6

メンバー関数ポインター型の戻り値の型に基づいて、クラス テンプレート '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': 複数の部分的な特殊化がテンプレート引数リストと一致します

http://ideone.com/ekWGg で示されているように、同じコードが GCC-4.3.4 で受け入れられて
います。

ただし、私は恐ろしく煩わしい回避策を考え出しました(少なくともこの特定のユースケースでは。より一般的な解決策を歓迎します):

#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> {};
4

1 に答える 1

3

これはバグです。

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

14.5.4.2 によると、これら 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 によると、これら 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())演繹は明らかに決して成功しません。voidty6

したがって、関数テンプレート 3 は関数テンプレート 4 よりも特殊化されています。また、クラス テンプレートの特殊化 1 は、クラス テンプレートの特殊化 2 よりも特殊化されています。したがって、special<void(s::*)()>両方の特殊化に一致しますが、明確に特殊化 1 をインスタンス化します。

于 2011-02-24T22:36:17.603 に答える