boost::result_of<>で __stdcall な関数の戻り値を得られないのでどうにかしてみた

どうやら boost::result_of は __stdcall などの修飾子が付いている関数に対応していないようです。

// これはOK (s_result_type は int)
typedef int (* success_t)();
typedef boost::result_of<success_t()>::type s_result_type;
s_result_type a = 0;

// これはNG (e_result_type は void)
typedef int (__stdcall * error_t)();
typedef boost::result_of<error_t()>::type e_result_type;
e_result_type b = 0;

Boost.Bindなどを参考に上記のNGのパターンに対応できるようにしてみました。

以下ソース。Gist にも置いてみました。

result_of_s.hpp の先頭の BOOST_RESULT_OF_S_CC を __fastcall に置き換えれば __fastcall な関数にも対応できるつもりですが未確認です。VS2005(VC8)でコンパイルが通ることを確認しています。

// result_of_s.hpp
#ifndef BOOST_RESULT_OF_S_HPP
#define BOOST_RESULT_OF_S_HPP

#ifndef BOOST_RESULT_OF_S_NUM_ARGS
#  define BOOST_RESULT_OF_S_NUM_ARGS 10
#endif

// original
#include <boost/utility/result_of.hpp>
#define BOOST_RESULT_OF_S_CC __stdcall

namespace boost {

template<typename F> struct result_of;

#if !defined(BOOST_NO_SFINAE) && !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
namespace detail {

template<typename F, typename FArgs, bool HasResultType> struct result_of_impl;

template<typename R>
struct result_of_void_impl<R (BOOST_RESULT_OF_S_CC *)(void)>
{
  typedef R type;
};

template<typename R>
struct result_of_void_impl<R (BOOST_RESULT_OF_S_CC &)(void)>
{
  typedef R type;
};

} // end namespace detail

// result_of_s.hpp と result_of_iterate_s.hpp が同じフォルダにある、という前提
#define BOOST_PP_ITERATION_PARAMS_1 (3,(0,BOOST_RESULT_OF_S_NUM_ARGS,"result_of_iterate_s.hpp"))
#include BOOST_PP_ITERATE()

#else
#  define BOOST_NO_RESULT_OF 1
#endif

}

#undef BOOST_RESULT_OF_S_CC

#endif // BOOST_RESULT_OF_S_HPP
// result_of_iterate_s.hpp
#if !defined(BOOST_PP_IS_ITERATING)
# error Boost result_of - do not include this file!
#endif

// CWPro8 requires an argument in a function type specialization
#if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3002)) && BOOST_PP_ITERATION() == 0
# define BOOST_RESULT_OF_S_ARGS void
#else
# define BOOST_RESULT_OF_S_ARGS BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),T)
#endif

#undef BOOST_RESULT_OF_S_ARGS

#if BOOST_PP_ITERATION() >= 1 

namespace detail {

template<typename R,  typename FArgs BOOST_PP_COMMA_IF(BOOST_PP_ITERATION())
         BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),typename T)>
struct result_of_impl<R (BOOST_RESULT_OF_S_CC *)(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),T)), FArgs, false>
{
  typedef R type;
};

template<typename R,  typename FArgs BOOST_PP_COMMA_IF(BOOST_PP_ITERATION())
         BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),typename T)>
struct result_of_impl<R (BOOST_RESULT_OF_S_CC &)(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),T)), FArgs, false>
{
  typedef R type;
};

#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551))
template<typename R, typename FArgs BOOST_PP_COMMA_IF(BOOST_PP_ITERATION())
         BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),typename T)>
struct result_of_impl<R (BOOST_RESULT_OF_S_CC T0::*)
                     (BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_ITERATION(),T)),
                 FArgs, false>
{
  typedef R type;
};

template<typename R, typename FArgs BOOST_PP_COMMA_IF(BOOST_PP_ITERATION())
         BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),typename T)>
struct result_of_impl<R (BOOST_RESULT_OF_S_CC T0::*)
                     (BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_ITERATION(),T))
                     const,
                 FArgs, false>
{
  typedef R type;
};

template<typename R, typename FArgs BOOST_PP_COMMA_IF(BOOST_PP_ITERATION())
         BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),typename T)>
struct result_of_impl<R (BOOST_RESULT_OF_S_CC T0::*)
                     (BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_ITERATION(),T))
                     volatile,
                 FArgs, false>
{
  typedef R type;
};

template<typename R, typename FArgs BOOST_PP_COMMA_IF(BOOST_PP_ITERATION())
         BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),typename T)>
struct result_of_impl<R (BOOST_RESULT_OF_S_CC T0::*)
                     (BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_ITERATION(),T))
                     const volatile,
                 FArgs, false>
{
  typedef R type;
};
#endif

}
#endif