我意识到这是错误的,但我无法删除它

I realized this is wrong but I could not delete it

本文关键字:删除 意识到 错误      更新时间:2023-10-16

作者:这当然做不到。从下面的答案中学习。

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

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

使用函数指针?

typedef (char)(*FP)(unsigned);
// AFAIK not possible in C++
FP x = y ;

我可以使用lambdas:

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

但是我不知道没有lambda如何做到这一点。有什么想法吗?

每当你可以编写 typedef 时,你也可以编写一个没有 typedef 的变量声明,语法几乎相同。

例:

// typedef
typedef char(*FP)(unsigned);
FP x = y ;
// no typedef
char(*x)(unsigned) = y;

删除typedef关键字,您将拥有一个变量声明。如果需要,可以在其上打上初始化。

您可以使用auto

auto fptr = &f;

它跳过了对 typedef 的需求并保留了一个很好的语法。

它与 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);

但是我不知道在没有 lambda 的情况下如何做到这一点。有什么想法吗?

只是不要使用 lambda 而是使用函数:

typedef char(*FP)(unsigned);   
char foo(unsigned){ return 0;}
int main() {
FP x = foo;
}

函数指针类型定义相当讨厌,如果你能更好地使用using

using FP = char(*)(unsigned);

现场演示

嗯...如果您使用的是 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, "!" );

非常感谢大家提供有用的评论的生动过山车。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中的错误,我今天报告了。

代码:

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 编译器的早期版本,确实通过执行运行时代码生成来支持此类赋值。