如何获取 C++ 的签名绑定(...)表达式

发布于 2024-10-13 19:09:35 字数 2786 浏览 0 评论 0原文

我正在尝试编写一个名为signature_of 的元函数,给定函数(指针)、函子或lambda 的类型,它返回其签名。

这是我到目前为止所得到的:

#include <boost/mpl/pop_front.hpp>
#include <boost/mpl/push_front.hpp>
#include <boost/function_types/is_member_function_pointer.hpp>
#include <boost/function_types/function_type.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/function_types/parameter_types.hpp>

#include <type_traits>

template <typename F>
struct signature_of_member
{
    typedef typename boost::function_types::result_type<F>::type result_type;
    typedef typename boost::function_types::parameter_types<F>::type parameter_types;
    typedef typename boost::mpl::pop_front<parameter_types>::type base;
    typedef typename boost::mpl::push_front<base, result_type>::type L;
    typedef typename boost::function_types::function_type<L>::type type;
};

template <typename F, bool is_class>
struct signature_of_impl
{
    typedef typename boost::function_types::function_type<F>::type type;
};

template <typename F>
struct signature_of_impl<F, true>
{
    typedef typename signature_of_member<decltype(&F::operator())>::type type;
};

template <typename F>
struct signature_of
{
    typedef typename signature_of_impl<F, std::is_class<F>::value>::type type;
};

它非常简单,大部分实际工作是由 boost::function_types 库完成的。 总体思路是:

  • 使用std::is_class来区分 内置函数之间(包括 lambdas)和
  • 内置函数类型的函子,使用 boost::function_types::function_type 来获取
  • 函子的签名,获取其operator()的类型,获取其签名,并修改它以删除“this”参数

This适用于内置函数:

int f(int);
typedef signature_of<decltype(f)>::type Sig;  // Sig is int(int)

适用于 lambda:

auto f = [](int) { return 0; }
typedef signature_of<decltype(f)>::type Sig;  // Sig is int(int)

和函子:

struct A
{
    int operator()(int);
};
typedef signature_of<A>::type Sig;  // Sig is int(int)

但是,它不适用于 bind() 表达式(这是函子的特殊情况)。如果我尝试这样做:

#include <functional>
int g(int);
typedef signature_of<decltype(std::bind(g, 0))>::type Sig;

我得到一个编译器错误:

In file included from test.cpp:3:0:
signature_of.hpp: In instantiation of 'signature_of_impl<
        _Bind<int (*(int))(int)>, true
    >':
signature_of.hpp:45:74:   instantiated from 'signature_of<
        _Bind<int (*(int))(int)>
    >'
test.cpp:21:52:   instantiated from here
signature_of.hpp:39:74: error: type of '& _Bind<
        int (*)(int)({int} ...)
    >::operator()' is unknown

问题是bind()返回的函子的operator()是一个模板,因此无法确定其类型。

是否可以通过其他方式获取bind()表达式的签名?

I am trying to write a metafunction named signature_of which, given the type of a function (pointer), functor, or lambda, returns its signature.

Here's what I have so far:

#include <boost/mpl/pop_front.hpp>
#include <boost/mpl/push_front.hpp>
#include <boost/function_types/is_member_function_pointer.hpp>
#include <boost/function_types/function_type.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/function_types/parameter_types.hpp>

#include <type_traits>

template <typename F>
struct signature_of_member
{
    typedef typename boost::function_types::result_type<F>::type result_type;
    typedef typename boost::function_types::parameter_types<F>::type parameter_types;
    typedef typename boost::mpl::pop_front<parameter_types>::type base;
    typedef typename boost::mpl::push_front<base, result_type>::type L;
    typedef typename boost::function_types::function_type<L>::type type;
};

template <typename F, bool is_class>
struct signature_of_impl
{
    typedef typename boost::function_types::function_type<F>::type type;
};

template <typename F>
struct signature_of_impl<F, true>
{
    typedef typename signature_of_member<decltype(&F::operator())>::type type;
};

template <typename F>
struct signature_of
{
    typedef typename signature_of_impl<F, std::is_class<F>::value>::type type;
};

It's pretty straightforward, with most of the real work being done by the boost::function_types library.
The general idea is:

  • use std::is_class to discriminate
    between built-in functions (including
    lambdas) and functors
  • for built-in function types, use boost::function_types::function_type to get its signature
  • for functors, get the type of their operator(), get its signature, and doctor it to remove the "this" parameter

This works for built-in functions:

int f(int);
typedef signature_of<decltype(f)>::type Sig;  // Sig is int(int)

for lambdas:

auto f = [](int) { return 0; }
typedef signature_of<decltype(f)>::type Sig;  // Sig is int(int)

and for functors:

struct A
{
    int operator()(int);
};
typedef signature_of<A>::type Sig;  // Sig is int(int)

However, it doesn't work for bind() expressions (which are a special case of functors). If I try this:

#include <functional>
int g(int);
typedef signature_of<decltype(std::bind(g, 0))>::type Sig;

I get a compiler error:

In file included from test.cpp:3:0:
signature_of.hpp: In instantiation of 'signature_of_impl<
        _Bind<int (*(int))(int)>, true
    >':
signature_of.hpp:45:74:   instantiated from 'signature_of<
        _Bind<int (*(int))(int)>
    >'
test.cpp:21:52:   instantiated from here
signature_of.hpp:39:74: error: type of '& _Bind<
        int (*)(int)({int} ...)
    >::operator()' is unknown

The problem is that the operator() of the functor returned by bind() is a template, and so its type cannot be determined.

Is it possible to get the signature of a bind() expression another way?

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

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

发布评论

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

评论(2

热鲨 2024-10-20 19:09:35

除了绑定器的operator()是模板化的事实之外,你还遇到了更多的问题,它还有任意数量的参数。请记住,您应该能够使用任意数量的额外参数调用绑定的结果。例如:

int f(int);

auto bound = boost::bind(f, _2);

现在可以使用 2 个或更多的任意数量的参数调用 bound,但实际上只有第二个参数被转发到函数。

所以基本上,正如另一个答案所说,这个对象没有签名。它的签名仅由它的使用方式定义。

You've got more problems than the fact that a binder's operator() is templated, it also has an arbitrary count of parameters. Remember that you're supposed to be able to invoke the result of bind with any number of extra arguments. For example:

int f(int);

auto bound = boost::bind(f, _2);

bound may now be called with any number of arguments of 2 or more, only the second is actually forwarded on to the function.

So basically, as another answer said, this object has no signature. It's signature is defined only by how it is used.

記憶穿過時間隧道 2024-10-20 19:09:35

如果运算符是模板化的,则它没有签名。

If the operator is templated, then it doesn't have a signature.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文