5

假设你有一个函子:

struct MyFunctor
{
    bool operator ()( int value )
    {
        return true;
    }
};

是否可以检索仿函数成员的参数类型以在模板中使用?以下是这个神秘功能的使用:

template < typename FunctorType >
bool doIt( FunctorType functor, typename FunctorType::operator()::arg1 arg )
{
    return functor( arg );
}

是否有有效的语法可以代替我的神话FunctorType::operator()::arg1

4

4 回答 4

7

如果您知道该项目是函子,那么您可以抓住它operator(),如下所示:

#include <iostream>

template <unsigned Idx, typename... T>
struct pick
{
    static_assert(Idx < sizeof...(T), "cannot index past end of list");
};

template <typename T, typename... TRest>
struct pick<0U, T, TRest...>
{
    typedef T result;
};

template <unsigned Idx, typename T, typename... TRest>
struct pick<Idx, T, TRest...>
{
    typedef typename pick<Idx-1, TRest...>::result result;
};

template <typename Func>
struct func_traits;

template <typename TObj, typename R, typename... TArgs>
struct func_traits<R (TObj::*)(TArgs...)>
{
    typedef R result_type;

    template <unsigned Idx>
    struct argument
    {
        typedef typename pick<Idx, TArgs...>::result type;
    };
};

template <typename Func,
          typename Traits = func_traits<Func>,
          typename R = typename Traits::result_type,
          typename Arg0 = typename Traits::template argument<0>::type,
          typename Arg1 = typename Traits::template argument<1>::type
         >
void foo(Func f)
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
};

struct thing
{
    void operator()(long, int*) { }
};

int main()
{
    foo(&thing::operator());
}

对我来说,该程序打印出来:

void foo(Func) [with Func = void (thing::*)(long int, int*), Traits = func_traits<void (thing::*)(long int, int*)>, R = void, Arg0 = long int, Arg1 = int*]

关键是Arg0和分别Arg1longint*

于 2012-05-01T15:40:01.443 回答
4

不,那里没有。最优雅的方法是要求你的函子为typedef参数类型提供一个,或者引入一个特征类。如果您希望模板与仿函数和函数一起使用,后者很有用。

或者,您可以将参数类型设置为第二个模板参数:

template < typename FunctorType, class ArgumentType >
bool doIt( FunctorType functor, ArgumentType arg )
{
    return functor( arg );
}

ArgumentType如果与仿函数所需的类型不匹配,编译器仍然会报错。

于 2011-07-12T16:16:47.270 回答
3

你可以用 C++0x 来做

template <typename... Args>
struct Function {
    typedef std :: tuple <Args...> args;
    void call () (Args... args);
}

template <typename... Args>
void do_it (Function<Args...>::args:: SOMETHING :: type t, Args... args) {
    something (t)
    Function <Args...> :: call (args...);
}
于 2011-07-12T16:37:28.567 回答
2

在这里,我对@BjörnPollex(正确)答案进行了 C++11 更新。

回到问题,您想明确指定的第二个参数doIt主要是为了限制可以传递的内容。在 C++11 中,您可以在不明确知道函子的参数类型的情况下暗示此限制(如果函子重载,则定义不明确)。

template < typename FunctorType, class ArgumentType >
auto doIt( FunctorType functor, ArgumentType arg ) -> decltype(bool(functor(arg)))
{
    return functor( arg );
}

(转换为bool甚至可能没有必要,我把它放在这里是因为您似乎真的希望返回类型为bool)。

doIt(模板)函数将采用任何可能与参数兼容的functor参数(并且也可转换为bool)。如果传递的参数不兼容,该函数甚至根本不存在,并且会产生一个优雅的“doIt function not found”编译器错误。

通过使用完美前移可以更进一步,使其doIt完全等同于functor(arg)

template < typename F, class A >
auto doIt( F&& f, A&& a ) -> decltype(bool(std::forward<F>(f)(std::forward<A>(a))))
{
    return std::forward<F>(f)( std::forward<A>(a) );
}
于 2014-01-25T18:54:46.507 回答