在一行中声明和定义函数指针变量

时间:2019-02-06 15:42:37

标签: c++ lambda function-pointers

在C ++中,我们如何执行以下操作

// fundamental language construct        
   type name = value ; 
// for example 
   int x = y;

带有功能指针?

 typedef (char)(*FP)(unsigned);

 // AFAIK not possible in C++
 FP x = y ;

我可以使用lambda:

 FP x = []( unsigned k) -> char { return char(k); }

但是我不知道如何在没有lambda的情况下执行此操作。有什么想法吗?

7 个答案:

答案 0 :(得分:13)

您可以使用auto fptr = &f;

    public static void test(String a)
     {

        char[] tochar=a.toCharArray();          



        int b[]=new int[a.length()];
        for(int i=0;i<b.length;i++)
        {
            b[i]=(int)(tochar[i]);
        }

        for(int i=0;i<b.length;i++)
            System.out.println(b[i]);


     }

 public static void main (String[] args)
{
test("55354");  }

它跳过了对typedef的需求,并保留了一个不错的语法。

答案 1 :(得分:12)

只要可以编写typedef,就可以使用几乎相同的语法编写不带typedef的变量声明。

示例:

main_window.close()

删除 // typedef typedef char(*FP)(unsigned); FP x = y ; // no typedef char(*x)(unsigned) = y; 关键字,您将获得一个变量声明。如果需要,可以对其进行拍打。

答案 2 :(得分:6)

它与Lambdas几乎相同,但我认为很难理解:

void my_int_func(int x)
{
    std::cout << "ther param is: " << x << std::endl;
}

//
int main(int argc, char *argv[])
{
    void (*foo)(int) = my_int_func;
    foo(1);

答案 3 :(得分:4)

  

但是我不知道如何在没有lambda的情况下执行此操作。有什么想法吗?

只使用lambda而不是函数:

typedef char(*FP)(unsigned);   

char foo(unsigned){ return 0;}

int main() {
    FP x = foo;
}

如果可以更好地使用using,则函数指针typedef很讨厌:

using FP = char(*)(unsigned);

Live Demo

答案 4 :(得分:2)

好吧...如果您使用的是lambda,则还可以使用auto

auto x = foo;

以下是带有static_assert()的完整编译示例,用于验证获得的类型

#include <type_traits>

char foo (unsigned)
 { return ' '; }

int main ()
 {
   auto x = foo;

   static_assert( std::is_same<decltype(x), char(*)(unsigned)>::value, "!" );
 }

auto与lambda一起使用,就像将其与FP一起使用

auto y = []() ->bool { return true; };

导致不同的结果:上方y的类型是带有operator()的未命名类,而不是指向该operator()的函数指针类型。

如果要使用函数指针,则必须使用运算符+将lambda转换为它,您可以使用以下static_assert()进行验证

auto y = +[]() ->bool { return true; };

static_assert( std::is_same<decltype(y), bool(*)()>::value, "!" );

答案 5 :(得分:1)

非常感谢大家对有用评论的热烈欢迎。在Reddit上,有人问我同样的问题,用户名为“ TheTiefMaster”,掉了这个“一个衬里”:

// also works as C
char whatever(unsigned k) { return char(k); } char(*F)(unsigned) = whatever;

让我澄清一下:我确实理解这是一行上的两个陈述。而且这里没有类型,只有一个指向同一函数的函数指针。用法:

    auto x = whatever(65); // 'A'
    auto y = F(66); // 'B'

然后我想出以下内容将对函数定义及其类型进行声明:

    // FP is a type of function whoever
    char whoever(unsigned k) { return 'A'; } typedef char(*FP)(unsigned) ;

呼叫行为符合预期的人

   auto w = whoever(42) ; // 'A'

FP是开始变得有趣的地方。 FP是一种类型,事实证明可以将其转换为该类型。

     // using FP as a type
     // c++ style type cast
     // empty cast returns nullptr
     auto fun = FP();
     // calling fun() above crashes
     // but it is "invocable" as per C++ rules
     static_assert(std::is_invocable_v<P2F()>);

将任何参数传递给此强制转换,可以工作并返回非空地址:

      // update: this compiles only on MSVC
      // and is a bug
      auto fun = FP(42); 
      // type of fun is char (*) (unsigned)

调用此乐趣的结果显然会崩溃:

     // reading access violation
     fun(123) ;

此强制转换带有任何所需函数的实例,可以起作用:

    auto fun = FP(whatever); 

    // works, obviously
    fun(65) ; // 'A'

要使用此知识,我们将使用static_cast安全地转换为我们可以调用的内容。 C ++类型转换过于强制,就像C风格类型转换一样。

     // does not compile
     // fun is the wrong type and can not be called
     auto fun = static_cast<FP>(42); 

     // does compile, fun is safe to call
         auto fun = static_cast<FP>(whatever);

    // works, obviously
    fun(65) ; // 'A'

这项调查显然还没有结束。我将在其他地方继续进行。

更新:

       using FP = char (*)(int) ;
       // must not compile, compiles under MSVC
       auto oops = FP(42) ;

是MSVC中的错误,我今天报告了它。

答案 6 :(得分:0)

代码:

typedef char(*FP)(int);
FP x = y;

如果y是捕获变量的lambda表达式,则无法使用当前的C ++编译器进行编译。

// Compiles OK
FP x0 = [](int k) -> char { return char(k); };

// Fails to compile
int i = 123;
FP x1 = [=](int k) -> char { return char(k); };
FP x2 = [=](int k) -> char { return char(k+i); };
FP x3 = [&](int k) -> char { return char(k+i); };
FP x4 = [i](int k) -> char { return char(k+i); };
// error: cannot convert ‘main()::<lambda(int)>’ to ‘FP {aka char (*)(int)}’
//        in initialization

之所以无法编译,是因为x1 ... x4的赋值右侧的大小大于FP的大小。

要使C ++编译器对x1 ... x4进行赋值是有效的,则需要在运行时生成代码。当前的C ++编译器(例如GCC和clang)不支持此功能,主要是因为C ++不是垃圾收集语言,否则会导致内存泄漏。一些垃圾收集的语言实现(例如官方Go编译器的早期版本)通过执行运行时代码生成来支持此类分配。