是否可以从(函子成员的)函数签名中检索参数类型以在模板中使用?

发布于 2024-11-19 11:02:28 字数 421 浏览 1 评论 0原文

假设您有一个函子:

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

Assume you have a functor:

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

Is it possible to retrieve a functor's member's argument type for use within your template? The following is a use of this mythical functionality:

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

Is there a valid syntax that would substitute for my mythical FunctorType::operator()::arg1 ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

迷爱 2024-11-26 11:02:28

如果您知道该项目是一个函子,那么您可以直接获取它的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 Arg1 分别是 longint*

If you know the item is a functor, then you can just grab its operator(), like so:

#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());
}

For me, that program prints out:

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*]

The key point being that Arg0 and Arg1 are long and int*, respectively.

东风软 2024-11-26 11:02:28

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

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

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

如果 ArgumentType 与函子所需的类型不匹配,编译器仍然会抱怨。

No there is not. The most elegant way to do this would be to either require your functors to provide a typedef for the argument-type, or to introduce a traits-class. The latter is useful if you want your template to work with functors and functions.

Alternatively, you can just make the argument type a second template parameter:

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

The compiler will still complain if ArgumentType does not match the type required by the functor.

一片旧的回忆 2024-11-26 11:02:28

你可以用 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...);
}

You can sort of do it in 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...);
}
久隐师 2024-11-26 11:02:28

在这里,我对 @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(模板)函数将采用可能与函子参数兼容的任何参数(也可转换为 bool)。如果传递的参数不兼容,该函数甚至根本不存在,并且会产生一个优雅的“doIt function not found”编译器错误。

我们可以更进一步,使用完美前向使 doItfunctor(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) );
}

Here I give a C++11 update to @BjörnPollex (correct) answer.

Going back the question, you want to specify the second argument of doIt explicitly mainly to restrict what can be passed. In C++11 you can imply this restriction without knowing explicitly the argument type of the functor (which is not well defined if the functor overloaded anyway).

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

(the conversion to bool may not be even necessary, I put it here because it seem that you really want the return type to be bool).

This doIt (template) function will take any argument that is possibly compatible with a functor argument (and also convertible to bool). If the argument passed is not compatible the function will not even exist at all, and will produce an elegant "doIt function not found" compiler error.

One can go one step more by using perfect forward to make doIt exactly equivalent to 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) );
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文