在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;
}
函数指针typedef相当讨厌,如果你可以更好地使用using
:
using FP = char(*)(unsigned);
嗯...如果你使用lambdas,你也可以使用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()>);
将任何参数传递给此强制转换,工作并返回非null地址:
// 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编译器的早期版本,通过执行运行时代码生成来支持这样的分配。