Capture function argument type from actual arguments

Is it possible to capture the type of a formal argument, having only the function name and the actual arguments?

I would need something similar to decltype, but it should return the function type instead of the return type of the function.

I found a half solution with C++11. If the function is not overloaded, you can use decltype to get the signature, specifying only the function name and template arguments (if any), but not the actual arguments:

template<class F>
struct my_function_traits;

// function pointer
template<class R, class Arg>
struct my_function_traits<R(*)(Arg)> : public my_function_traits<R(Arg)>
{
  typedef Arg type;
};

template<class R, class Arg1>
struct my_function_traits<R(Arg1)>
{
  typedef Arg1 type;
};

namespace itk
{
template <typename PixelType, unsigned Dimension>
class Image;
}

template <typename TPixel, unsigned VDimension>               
void func2(itk::Image<TPixel, VDimension>* image) {}


int main()
{
  typedef my_function_traits< decltype(func2<int, 2>) > Traits;

  Traits::type var = 0;

  return 0;
}

This works well, but if I add this other function, decltype will not able to resolve the type:

template <typename TPixel, unsigned VDimension>               
void func2(const itk::Image<TPixel, VDimension>* image, int i) {}

What makes sense, because the function name is ambiguous and both versions have the same template arguments. But the compiler must be able to figure out the correct function from the static type of the actual arguments. The problem is that as soon as I specify them, decltype returns the type of the expression, ie the return type of the function.

  itk::Image<int, 3>* image;
  int a = 3;
  ...
  typedef my_function_traits< decltype(func2<int, 2>(image, 3)) > Traits;

My main goal is to check the constness of the first argument.

Thanks for any help!


Assuming that you don't know the constness of the first pointer, and you know successive argument type, you may use the following:

template <typename T, typename ...Ts>
struct is_first_arg_const_ptr
{
    template <typename Ret>
    static std::false_type
    is_const(Ret (&f)(T*, Ts...));

    template <typename Ret>
    static std::true_type
    is_const(Ret (&f)(const T*, Ts...));

    // And for methods
    template <typename Ret, typename C>
    static std::false_type
    is_const (Ret (C::*) (T*, Ts...)) /* const volatile & && */;

    template <typename Ret, typename C>
    static std::true_type
    is_const (Ret (C::*) (const T*, Ts...)) /* const volatile & && */;

    // .. complete for all combinations of cv_qualifier and ref
};

And now, the overload is correctly chosen without ambiguity.

Live example.

For the macro, you may do something like:

template <typename T, typename ...Ts>
constexpr
auto make_is_first_arg_const_ptr(T&& t, Ts&&...)
-> is_first_arg_const_ptr<
    typename std::decay<decltype(*t)>::type,
    typename std::decay<Ts>::type...
>;

#define IS_FIRST_ARG_CONST_PTR(Name, ...) 
    (decltype(make_is_first_arg_const_ptr(__VA_ARGS__).is_const(Name))::value)

And then use it as

static_assert(!IS_FIRST_ARG_CONST_PTR(func2, image), "");
static_assert(IS_FIRST_ARG_CONST_PTR(func2, image, a), "");
static_assert(IS_FIRST_ARG_CONST_PTR(&MyClass::func2, image, a), "");

Note that the macro will not work for some prototype of func as I deduce type from argument but you will get a compile error in this case (you may change std::decay by a more appropriate traits to match your need).


Boost does this. Have a look at boost's function_traits:

http://www.boost.org/doc/libs/1_55_0/boost/type_traits/function_traits.hpp

http://www.boost.org/doc/libs/1_55_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html

链接地址: http://www.djcxy.com/p/66506.html

上一篇: 为什么返回类型中的decltype表达式必须在符号名称中被改变?

下一篇: 从实际参数捕获函数参数类型