【问题标题】:How to get function signature from arguments?如何从参数中获取函数签名?
【发布时间】:2020-06-17 19:26:42
【问题描述】:

假设我有一个这样的函数f

void f(int x) {
   cout << "Hi I'm f" << endl;
}

auto x = f;

但是如果函数重载了,这个就不行了:

void f(int x) {}
void f(int x, const int y) {}

auto x = f; // Which one to use ?

所以这是不可能的。但是让我们假设我知道我将传递给函数的参数,例如我知道我想调用f(10, 20)。不是参数本身的类型,而是实际值,它们可能在 constness、reference-ness(假设这个词存在......)甚至通过强制转换的不同类型方面有所不同。在示例中,20int&amp;&amp;,并且参数 const int 是可绑定的。我还假设没有边缘情况,并且值只能绑定到一个重载,即使直接调用也无法编译。是否可以推导出重载函数的地址和函数的签名?

伪代码:

Input: Values of arguments
Output: Address of overloaded function `f` OR function signature type (any one can be deduced from the other though)

明明可以直接调用,但是函数确实“偷偷摸摸”,直接调用,貌似不可能被引用。

template<typename... Args>
void callMeMaybe(Args... args) {
    f(args...); // I can call f... But how to get f itself ?
    auto x = static_cast<void(Args...)>(f) // does not works because f could differ in argument bind
}

【问题讨论】:

  • 你要签名做什么?根据您正在做/试图完成的工作,您甚至可能不需要它。
  • 根据您的开发环境,您可能会使用 __FUNCTION__ 或 __FUNC__ 预处理器,如下所述:gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
  • 我想使用类似std::bind 的对象,该对象将按引用存储引用并按值存储值。 std::bind 按值存储他的所有参数,我不想使用 std::refstd::cref。还要注意的是,类型值/引用应该从f 的签名中推断出来,而不是从std::bind-like 对象的调用(这里像callMeMaybe 但它不起作用)
  • 您可以使用像 auto x = [](auto&amp;&amp;... x) -&gt; decltype(f(std::forward&lt;decltype(x)&gt;(x)...)) { return f(std::forward&lt;decltype(x)&gt;(x)...); }; 这样的 lambda 来获得这种行为。如果需要,您只需要指定它如何捕获。
  • 使用 lambdas,你试图解决的问题甚至不存在了。

标签: c++


【解决方案1】:

调用哪个函数取决于您正确提到的参数的引用性/常量性。您必须明确告诉编译器签名,然后您将能够获取函数指针。有趣的是,这也适用于模板。

#include<iostream>

template<typename Name1, typename Name2, typename Name3>
Name3 f(Name1, Name2, Name3);

int f(int);
int f(int,int const);

using namespace std;

int main()
{
    //Type deduction using decltype: the args must be constexpr.
    //Remember there is no runtime-reflection support in c++ yet.
    auto s = static_cast< int (*)(decltype(78), decltype(-98) ) > (f);
    cout << s(78, -98) << endl;
    cout << typeid(s).name() << endl;

    // x and y will point to the same function
    // int (*)(int) and int (*)(const int) are equivalent overloads
    auto x = static_cast<int (*)(int)>( f );
    auto y = static_cast<int (*)(int const)>( f );

    //p and q will point to the same function
    // int (*)(int, int) and int (*)(int, const int) are equivalent overloads
    auto p = static_cast<int (*)(int, int const)>( f );
    auto q = static_cast<int (*)(int, int)>( f );

    //With templates
    auto z = static_cast<string (*)(int, char, string)>( f );
    cout << z(4,'a',"Hello!!") << endl;

    //typeid to check signatures
    cout << typeid(x).name() << endl;
    cout << typeid(y).name() << endl;
    cout << typeid(p).name() << endl;
    cout << typeid(q).name() << endl;
    cout << typeid(z).name() << endl;

    return 0;
}

int f(int arg)
{
    return arg;
}

int f(int a1, int const a2)
{
    return a2; //Return the second element
}

template<typename Name1, typename Name2, typename Name3>
Name3 f(Name1 a, Name2 b, Name3 c)
{
    return c; // Return the 3rd element
}

【讨论】:

    猜你喜欢
    • 2022-08-04
    • 1970-01-01
    • 1970-01-01
    • 2021-01-19
    • 2021-02-18
    • 1970-01-01
    • 2018-05-23
    • 2018-12-19
    • 1970-01-01
    相关资源
    最近更新 更多