jeff_

jeff_ 查看完整档案

九江编辑  |  填写毕业院校  |  填写所在公司/组织 www.flowerdeer.cn/ 编辑
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 个人简介什么都没有

个人动态

jeff_ 赞了回答 · 2020-04-25

解决c/c++ 柔性数组 问题

我查资料发现柔性数组是没有分配地址的,

“没有分配地址”是什么意思 ....

这个最后的位置长度的数组,再计算大小的时候,结果为 0 。

请问为什么不管结构体test4 里面有都多少成员,指针p4+1的结果都是指向最后的柔性数组。

数组指针+1指向下一个成员,结构体指针+1为什么指向了最后?

这俩是一个问题:下一个成员的开始,不就是前一个成员的最后 ...

然后,“数组指针”是想说“指向数组成员的指针嘛 ...
再进行指针运算的时候,如果指针指向的不是一个数组成员,视为指向长度为1的数组的成员。

这是编译器优化的行为还是标准定义?

这个结构最后的没有长度的数组是 C 的,C++ 并没有。g++ 自己按照 C 的实现做的扩展。

关注 2 回答 1

jeff_ 赞了回答 · 2020-04-14

解决在堆中, 当一个变量占多个字节的内存时,变量的指针指向的是高地址还是低地址?

我想你把内存的生长方向与操作逻辑搞混了,这是两件事,堆跟栈的生长方向不同,是指分配的方向不同。但是对于一个变量或者一段内存块来说,不管在哪里,操作逻辑是相同的,操作逻辑,不会因为栈区或堆区而搞差异化操作,没必要并且也不应该有差异。
大小端是关系到数据的存放顺序,a1~4的输出,小端是4321,大端是1234,跟你的问题没关系
申请堆内存可以用malloc或者new

#include <stdio.h>
#include <stdlib.h>

int main()
{
  int a=0x01020304;
  
  unsigned char* a1=(unsigned char*)(&a);
  unsigned char* a2=(a1+1);
  unsigned char* a3=(a1+2);
  unsigned char* a4=(a1+3);
  
  
  printf("a:%x\n",  a);
  printf("a1:%d\n", *a1);
  printf("a2:%d\n", *a2);
  printf("a3:%d\n", *a3);
  printf("a4:%d\n", *a4);
  
  unsigned int* b = (unsigned int*)malloc(sizeof(unsigned int));
  *b = 0x01020304;
  
  unsigned char* b1=(unsigned char*)b;
  unsigned char* b2=(b1+1);
  unsigned char* b3=(b1+2);
  unsigned char* b4=(b1+3);
  
  printf("b:%x\n",  *b);
  printf("b1:%d\n", *b1);
  printf("b2:%d\n", *b2);
  printf("b3:%d\n", *b3);
  printf("b4:%d\n", *b4);
  
  free(b);
  
  return 0;
}

输出:

a:1020304
a1:4
a2:3
a3:2
a4:1
b:1020304
b1:4
b2:3
b3:2
b4:1

关注 3 回答 1

jeff_ 提出了问题 · 2020-04-14

解决在堆中, 当一个变量占多个字节的内存时,变量的指针指向的是高地址还是低地址?

已知

当一个变量占多个字节的内存时,变量的指针指向的是高地址还是低地址?在栈中指针指向的是最低地址的那个字节(大概知道是因为push的原因)

void main()
{
  int a=0x01020304;
  
  unsigned char* a1=(unsigned char*)(&a);
  unsigned char* a2=(a1+1);
  unsigned char* a3=(a1+2);
  unsigned char* a4=(a1+3);
  
  
  printf("a:%x\n",  a);
  printf("a1:%d\n", *a1);
  printf("a2:%d\n", *a2);
  printf("a3:%d\n", *a3);
  printf("a4:%d\n", *a4);
  
  return ;
}

输出结果:
image.png

提问

在堆中的实现不知道怎么写。

请教下:

  1. 当一个变量占多个字节的内存时,变量的指针指向的是高地址还是低地址?在堆中指针指向的是否也是最低地址的那个字节?
  2. 是否一个变量占多个字节都是从低到高?另外大小端有区别吗?
  3. 编译器一般对堆内存会怎么处理?

关注 3 回答 1

jeff_ 回答了问题 · 2020-03-21

解决在automake找不到.h头文件

应该是同级目录会自动导入.h文件。configure.ac 不需要添加 AC_CHECK_HEADERS([hello.h]),Makefile.amhello_SOURCES=hello.cpp hello.h 、hello_CPPFLAGS = -I/home/shiyanlou/automake 也只需要hello_SOURCES=hello.cpp 即可。 就是不知道 AC_CHECK_HEADERS 这是啥时候需要添加的了。

我参考个视频:
https://www.youtube.com/watch...

关注 1 回答 1

jeff_ 提出了问题 · 2020-03-21

解决在automake找不到.h头文件

在网上看了使用autoconf 和 automake 生成 Makefile 文件的文章,但大多都是只有一个.c文件的。 我自己加了个.h文件(和.cpp在同级目录)编译,但是运行./configure 时报错。

image.png

请教下大家这个.h文件应该怎么添加。
image.png

下面是我的Makefile.am文件

AUTOMAKE_OPTIONS=foreign
bin_PROGRAMS=hello
hello_SOURCES=hello.cpp hello.h
hello_CPPFLAGS = -I/home/shiyanlou/automake

以及我的configure.ac文件

\# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.69])
AC_INIT([hello], [1.0], [zhang6333778@gmail.com])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([hello.cpp])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CXX
AC_PROG_CC

# Checks for libraries.

# Checks for header files.
AC_CHECK_HEADERS([hello.h])

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_OUTPUT(Makefile)```

以及我使用命令生成的文件:

![image.png](/img/bVbERFf)

关注 1 回答 1

jeff_ 赞了回答 · 2020-02-26

解决关于右值、精确传递 (Perfect Forwarding)请教

std::forward函数通过类型推导+引用折叠等机制,最终会将你传入的T所具有的属性原封不动的传递下去,这就是精确传递(也叫做完美转发),move和它是一个层面的东西,仅是推导过程会将传入的T推导(update:推导这里用的不严谨,应该是通过类型萃取获得其原始类型的右值引用类型)为右值引用类型(type)的右值(value category)。
要理解这个东西你要先明白value category的机制 + 模板类型推导的机制 + 引用折叠的机制 + 左值/右值引用的机制,然后你打开任何一个版本的std::move和std::forward,能用上述机制推导出这两个函数是如何达到目的的就算理解了。
不是我刻意要回复的复杂,而是这个问题就是这么麻烦。。。推荐你一本书《effective modern c++》里面的相关章节能帮到你。

关注 2 回答 2

jeff_ 关注了问题 · 2020-02-26

贪心之影分身过河

我遇到一个算法题,感觉应该用贪心的思想做,但是用代码实在不知道怎么写,恳请大神们给一点思路。

问题描述

鸣人学会了影分身之术,召唤出了n个鸣人的分身,他想知道这些分身们能有多少渡过江面到达对岸。
鸣人的分身们可以两两配对,让一个分身先跳跃到空中,另一个分身跳跃到他的背上,踩背进行二次跳跃。虽然这样牺牲了一个分身,不过可以让更多的分身渡江。
请问鸣人的分身最多能有多少渡江?

输入

第一行输入正整数n与d(n<=10^6,d<=10^9),其中d表示离对岸的距离。
接下来n行,每行两个整数x与y(0<=x,y<=10^9),分别表示该分身第一次跳跃的最远距离和踩背二次跳跃的最远距离。

输出

输出鸣人的分身最多能有多少渡江。

样例展示

5 10
6 8
2 100
7 3
1 10
2 5

答案

2

关注 2 回答 0

jeff_ 提出了问题 · 2020-02-25

解决关于右值、精确传递 (Perfect Forwarding)请教

刚刚看了篇关于精确传递 (Perfect Forwarding)的文章,有点不理解的请教下大家。

文章中提到:精确传递适用于这样的场景:需要将一组参数原封不动的传递给另一个函数。

我自己写了个测试程序

 #include <iostream>
 #include <string>
 #include <type_traits>
 using namespace std;

/*
template <typename T>
int process_value(T&& val){
   cout << typeid(val).name() << endl;
   return 1;
}
*/

void process_value(int& i) {
 std::cout << "LValue processed: " << i << std::endl;
}
void process_value(const int& i) {
 std::cout << "const LValue processed: " << i << std::endl;
}
void process_value(int &&i) {
 std::cout << "RValue processed: " << i << std::endl;
}
void process_value(const int &&i) {
 std::cout << "const RValue processed: " << i << std::endl;
}

/*
template <typename T> void forward_value(const T& val) {
  cout << "const T&"<<endl;
  process_value(val);
}
*/

template <typename T> void forward_value(T&& val) { 
//      cout << "T&&" <<endl;
        process_value(val); 
}


int main(){
        int a = 0; 
        const int &b = 1; 
        forward_value(a); // int& 
        forward_value(b); // const int& 
        forward_value(2); // int&&

        return 0;
}

结果是:
image.png

请问下:
forward_value(2) 这里常量2不是应该是个右值嘛?

根据上文:精确传递将一组参数原封不动的传递给另一个函数。forward_value(T&& val) 传递给 process_value(val) 的参数不应该还是右值嘛?所以不是应该调用process_value(int &&i)函数嘛?为什么调用的是process_value(int& i)函数?

参考文章链接精确传递 (Perfect Forwarding)

关注 2 回答 2

jeff_ 赞了回答 · 2020-01-21

解决C++创建临时对象问题?

通常,声明变量会使用 int a; 。但是,使用 int (a); 同样是合法的。

于是,A(str); 就有了两种可能的解释,声明一个变量 str,类型为 A ;或者构造一个类型为 A 的临时变量,并将 str 作为构造函数的参数。在有这种歧义的时候,C++ 总是认为这是一个变量声明。

A("absf") 并没有这种歧义,它不能被解释为变量声明。

关注 4 回答 2

jeff_ 关注了用户 · 2020-01-19

fefe @fefe_5d0b30d7515e7

关注 57

jeff_ 赞了回答 · 2020-01-19

解决文件系统与内核的关系

文件系统实际是一种“格式”。它是文件/目录如何存储在存储介质(硬盘、软盘、光盘)上的一种格式约定。“exFAT”,“ntfs” 指的都是这种东西。

内核里的“文件系统”,实际是在内核里写的对应这些格式的读、写、创建、删除的一层 api 。他们对上层(应用程序)提供统一的接口,对下层(存储介质),则根据格式的不同执行不同的操作。所以“支持” ntfs ,就是在这一层 api 里,包含了对 ntfs 格式的硬盘的读写支持。不同格式的(内核)存取代码自然是不同的,编译进去了就支持,没有编译进去就不支持。

如果内核对上提供了读写裸盘的 api ,其实是可以在用户态,在某一应用程序中读写任何文件系统的(按照相应格式的标准读写就好了)。但是对所有应用提供统一接口是操作系统的事,应用搞不定。

内核其实不一定要有文件系统。如果这个系统就不需要操作本地存储介质的话(操作系统本身也是直接加载到内存里),其实可以没有文件系统支持,并且不对上(应用)提供文件操作 api 。

关注 2 回答 1

jeff_ 提出了问题 · 2020-01-19

解决文件系统与内核的关系

在使用RedHat7.5时,测试发现不支持exFAT ntfs文件系统,之前只知道它是管理文件的工具。它与内核有种鸡与蛋的关系,内核加载init需要文件系统,文件系统依靠内核工作?

但是我百度发现其他的Linux发行版有的可以支持ntfs。但是发行版都是使用linux内核,当然版本可能不同。因为关于操作系统的知识不是很扎实,请教下大家。

请问:

  • 1.文件系统本身是怎么运行的,其是否加载在内核,随内核启动后启动。
  • 2.文件系统本身是否属于内核态(kernel)而不是用户态(usr)?如果内核版本不支持比如exFAT,我们没有办法去安装?
  • 3.内核是否一定需要文件系统本身?

关注 2 回答 1

jeff_ 提出了问题 · 2020-01-04

解决关于代码注释的危害

在github的LTP项目(一个linux内核测试项目)的文档看到这么一句话不很理解,关于代码注释的危害.

Comments can sometimes save you day but they can easily do more harm than good. There has been several cases where comments and actual implementation were drifting slowly apart which yielded into API misuses and hard to find bugs. Remember there is only one thing worse than no documentation, wrong documentation.

image.png

我印象中不是鼓励大家进行代码注释嘛?这里面说Comments more harm than good 。
原因 :comments and actual implementation were drifting slowly apart
结果:API misuses and hard to find bugs.

因为自己英语不太好,用翻译软件也觉得生硬, 注释和实际实现之间的距离很近?导致API滥用和未知的错误?

请教下, 这几句到底是什么含义?API滥用以及未知的错误 又可能 会导致什么危害? 能举个具体的例子就更为感谢。

原文地址:https://github.com/linux-test...

关注 5 回答 4

jeff_ 赞了回答 · 2019-12-27

解决关于socket通信描述符fd的变化

1.listen_fd 为什么会被移出 working_set集合?是因为accept()函数会将listen_fd取出,然后将新的fd传入?还是我哪里理解有问题?
回答:select() 函数自身会修改传入的 fd_set 集合的内容。这是 value-result 类型的参数,所以传递的是指针地址。
传入的 fd_set 是所要监听的 fd 集合。
当 select() 函数返回后,所给的 fd_set 里面只保留 ready 的 fd集合,也就是可读、可写、或者发生异常的 fd 集合。
所以要使用 FD_ISSET() 函数检查特定 fd 是否还在 fd_set 集合里面。如果还在,说明这个 fd 发生了预期的事件,可以进行处理。

2.Recv(num)的num是否有存在的价值,似乎Recv()内部没有调用。
回答:从所给的代码来看,Recv()内部没有使用所传入的参数。看起来是不需要的。
可能是代码修改过程中遗留的函数参数。

关注 2 回答 1

jeff_ 提出了问题 · 2019-12-25

解决关于socket通信描述符fd的变化

最近开始看通信方面的文章,有一篇文章的代码有个关于描述符fd的变化,不知道具体原因请教下大家。

首先 设置了监听fd: listen_fd :
int listen_fd;

然后socket() 返回值指向listen_fd:
listen_fd = socket(PF_INET, SOCK_STREAM, 0);

再调用 bind() 把地址赋予 listen_fd :
bind(listen_fd, (struct sockaddr*)&server_addr, sizeof(server_addr))

监听 listen_fd :
listen(listen_fd, queue_len)

将listen_fd加入集合:
FD_SET(listen_fd, &master_set);

循环调用select():

while (1)
    {
        FD_ZERO(&working_set);
        memcpy(&working_set, &master_set, sizeof(master_set));

        timeout.tv_sec = 30;
        timeout.tv_usec = 0;

        int nums = select(max_fd + 1, &working_set, NULL, NULL, &timeout);
        if (nums < 0)
        {
            cout << "select() error!";
            exit(1);
        }

        if (nums == 0)
        {
            //cout << "select() is timeout!";
            continue;
        }

        if (FD_ISSET(listen_fd, &working_set))
            Accept();   // 有新的客户端请求
        else
            Recv(nums); // 接收客户端的消息
    }
}

问题:
FD_ISSET(listen_fd, &working_set),最后判断listen_fd 是否存在于 working_set 有点不解。
我自己再Accept()和RECV()里面加上了打印发现是先调用了Accept()一次,然后每次通信都会调用Recv(num)函数。

请问下:
1.listen_fd 为什么会被移出 working_set集合?是因为accept()函数会将listen_fd取出,然后将新的fd传入?还是我哪里理解有问题?
2.Recv(num)的num是否有存在的价值,似乎Recv()内部没有调用。

全部代码(来源: CSDN - 神奕- IO多路复用:select、poll、epoll示例 ):
/*************************************************************************
    > File Name: server.cpp
    > Author: SongLee
    > E-mail: lisong.shine@qq.com
    > Created Time: 2016年04月28日 星期四 22时02分43秒
    > Personal Blog: http://songlee24.github.io/
 ************************************************************************/
#include<netinet/in.h>   // sockaddr_in
#include<sys/types.h>    // socket
#include<sys/socket.h>   // socket
#include<arpa/inet.h>
#include<unistd.h>
#include<sys/select.h>   // select
#include<sys/ioctl.h>
#include<sys/time.h>
#include<iostream>
#include<vector>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<cstring>
using namespace std;
#define BUFFER_SIZE 1024

struct PACKET_HEAD
{
    int length;
};

class Server
{
private:
    struct sockaddr_in server_addr;
    socklen_t server_addr_len;
    int listen_fd;    // 监听的fd
    int max_fd;       // 最大的fd
    fd_set master_set;   // 所有fd集合,包括监听fd和客户端fd   
    fd_set working_set;  // 工作集合
    struct timeval timeout; 
public:
    Server(int port);
    ~Server();
    void Bind();
    void Listen(int queue_len = 20);
    void Accept();
    void Run();
    void Recv(int nums);
};

Server::Server(int port)
{
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htons(INADDR_ANY);
    server_addr.sin_port = htons(port);
    // create socket to listen
    listen_fd = socket(PF_INET, SOCK_STREAM, 0);
    if(listen_fd < 0)
    {
        cout << "Create Socket Failed!";
        exit(1);
    }
    int opt = 1;
    setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
}

Server::~Server()
{
    for(int fd=0; fd<=max_fd; ++fd)
    {
        if(FD_ISSET(fd, &master_set))
        {
            close(fd);
        }
    }
}

void Server::Bind()
{
    if(-1 == (bind(listen_fd, (struct sockaddr*)&server_addr, sizeof(server_addr))))
    {
        cout << "Server Bind Failed!";
        exit(1);
    }
    cout << "Bind Successfully.\n"; 
}

void Server::Listen(int queue_len)
{
    if(-1 == listen(listen_fd, queue_len))
    {
        cout << "Server Listen Failed!";
        exit(1);
    }
    cout << "Listen Successfully.\n";
}

void Server::Accept()
{
    struct sockaddr_in client_addr;
    socklen_t client_addr_len = sizeof(client_addr);

    int new_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &client_addr_len);
    if(new_fd < 0)
    {
        cout << "Server Accept Failed!";
        exit(1);
    }

    cout << "new connection was accepted.\n";
    // 将新建立的连接的fd加入master_set
    FD_SET(new_fd, &master_set);
    if(new_fd > max_fd)
    {
        max_fd = new_fd;
    }
}   

void Server::Run()
{
    max_fd = listen_fd;   // 初始化max_fd
    FD_ZERO(&master_set);
    FD_SET(listen_fd, &master_set);  // 添加监听fd

    while(1)
    {
        FD_ZERO(&working_set);
        memcpy(&working_set, &master_set, sizeof(master_set));

        timeout.tv_sec = 30;
        timeout.tv_usec = 0;

        int nums = select(max_fd+1, &working_set, NULL, NULL, &timeout);
        if(nums < 0)
        {
            cout << "select() error!";
            exit(1);
        }

        if(nums == 0)
        {
            //cout << "select() is timeout!";
            continue;
        }

        if(FD_ISSET(listen_fd, &working_set)){
            Accept();   // 有新的客户端请求
            cout << " Accept() will call" << endl;
        }
        else
            Recv(nums); // 接收客户端的消息
            cout << "  Recv() will call" << endl;
    }
}

void Server::Recv(int nums)
{
    for(int fd=0; fd<=max_fd; ++fd)
    {
        if(FD_ISSET(fd, &working_set))
        {
            bool close_conn = false;  // 标记当前连接是否断开了

            PACKET_HEAD head;
            recv(fd, &head, sizeof(head), 0);   // 先接受包头,即数据总长度

            char* buffer = new char[head.length];
            bzero(buffer, head.length);
            int total = 0;
            while(total < head.length)
            {
                int len = recv(fd, buffer + total, head.length - total, 0);
                if(len < 0)
                {
                    cout << "recv() error!";
                    close_conn = true;
                    break;
                }
                total = total + len;
            }

            if(total == head.length)  // 将收到的消息原样发回给客户端
            {
                int ret1 = send(fd, &head, sizeof(head), 0);
                int ret2 = send(fd, buffer, head.length, 0);
                if(ret1 < 0 || ret2 < 0)
                {
                    cout << "send() error!";
                    close_conn = true;
                }
            }

            delete buffer;

            if(close_conn)  // 当前这个连接有问题,关闭它
            {
                close(fd);
                FD_CLR(fd, &master_set);
                if(fd == max_fd)  // 需要更新max_fd;
                {
                    while(FD_ISSET(max_fd, &master_set) == false)
                        --max_fd;
                }
            }
        }
    }   
}

int main()
{
    Server server(15000);
    server.Bind();
    server.Listen();
    server.Run();
    return 0;
}

关注 2 回答 1

jeff_ 赞了回答 · 2019-12-22

解决lambda和std :: function之间的强制转换(关于结构继承自身偏特化版本)

它并不一定要继承自己的偏特化。换一个也可以,比如这样

template <typename> struct function_traits_base;

template <typename Function>
struct function_traits : public function_traits_base<decltype(&Function::operator())> {

};

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits_base<ReturnType(ClassType::*)(Args...) const>       {
    typedef std::function<ReturnType(Args...)> function;            
};

这样看得清楚一些,function_traits 是对外接口,但是需要 function_traits_base 的辅助来获得其对应得 std::function 特化。

这里,由于 function_traitsfunction_traits_base 都是只有一个类型模板参数,其生效得类型无交集(function_traits 只用于(实现了 operator() 的)类类型,function_traits_base 只用于指向成员函数的指针),所以原来的实现里就都使用了 function_traits ,没有引入另外的一个类型。

关注 2 回答 1

jeff_ 提出了问题 · 2019-12-21

解决lambda和std :: function之间的强制转换(关于结构继承自身偏特化版本)

关于C++ 特性不太熟悉,谷歌也因为不知道具体关键字而造成困难,于是又来请教大家。

代码是关于 lambda和std :: function之间的 无法进行强制转换 ,于是手动识别lambda 进行转换。

下面这里的结构体function_traits继承一个偏特化的版本是什么意思?

template <typename Function>
struct function_traits : public function_traits<decltype(&Function::operator())> {

};

原文链接(需fan墙):http://vitiy.info/c11-functional-decomposition-easy-way-to-do-aop/

测试代码(备注均为我自己添加,可能有错误)
#include <iostream>
#include <functional>

//using namespace std;

template <typename ...Args>
std::function<void(Args...)> wrapLog(std::function<void(Args...)> f) {

    return [f](Args... args) {                                            //捕获函数对象f
        std::cout << "start" << std::endl;
        f(args...);
        std::cout << "finish" << std::endl;
    };
}

template <typename Function>
struct function_traits : public function_traits<decltype(&Function::operator())> {

};

//lambda 转换为 std::function<void(Args...)> 需要知道 传入参数类型和返回值类型 ,这里进行萃取 
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>         //Args...可变模板参数 ,因为不知道lambda将传入几个参数
{
    //typedef ReturnType (*pointer)(Args...);
    typedef std::function<ReturnType(Args...)> function;            
};


template <typename Function>
typename function_traits<Function>::function    //返回值类型 function_traits<Function>::function
to_function(Function& lambda)                    //函数名to_function,传入参数lambda
{
    return typename function_traits<Function>::function(lambda);    //将lambda传入function_traits<Function>::function 
}

//functional里面有定义了个std::plus。如果把plus定义为global的,访问时在global查找定义就会和std::plus冲突,产生二义。
//auto plus = [](int a, int b) { std::cout << a + b << std::endl; };            //error,Plus不明确
std::function<void(int, int)> plus = [](int a, int b) { std::cout << a + b << std::endl; };

int main(int argc, char *argv[]) {
    //这是简单的lambda,其中包含琐碎的计算:
    //auto plus = [](int a, int b) { cout << a + b << endl; };

    //lambda和 std :: function 无法完成转换
    //auto loggedPlus = wrapLog(plus);                                                //test1

    //强制转换,OK,该行可以编译,但是很难看
    auto loggedPlus  = wrapLog(static_cast<std::function<void(int, int)>>(plus));   //test2
    loggedPlus(2, 3);

    //暂时最佳解决方案
    auto loggedPluss = wrapLog(to_function(plus));            //通过调用to_function函数 将 lambda表达式plus 转换为std::function<void(Args...)> 形式
    loggedPluss(2, 3);

    return 0;
}

关注 2 回答 1

jeff_ 赞了回答 · 2019-12-15

解决为什么lambda变量作为全局变量不支持作为函数参数传入

functional里面有定义了个std::plus。如果把plus定义为global的,访问时在global查找定义就会和std::plus冲突,产生二义。

p.s. 不建议直接用using namespace std;

关注 2 回答 1

jeff_ 提出了问题 · 2019-12-14

解决为什么lambda变量作为全局变量不支持作为函数参数传入

题目描述

看了一篇文章,其中有一段是关于lambda与std::function之间转换,具体就是将一个lambda变量作为参数传入一个需要std::function<void(Args...)> f 的函数。文章传送门:C ++ 11函数分解–做AOP的简便方法

因为我不小心将plus这个变量放在了全局段,在调用Plus时报错定义不明确(放在main内部作为局部变量可行)。我以为是匿名函数不能作为全局传值,于是又写了一个测试addPlus,但其是可行的。

请问,为什么lambda返回的变量不能作为作为函数参数传入?其会被认为是不明确的?能否举一个例子?谢谢

相关代码

#include <iostream>
#include <functional>

using namespace std;


template <typename ...Args>
std::function<void(Args...)> wrapLog(std::function<void(Args...)> f)
{
    return [f](Args... args) {
        cout << "start" << endl;
        f(args...);
        cout << "finish" << endl;
    };
}

int a = 10, b = 15;
int add(int i, int j) {
    return i + j;
}

auto plus = [](int a, int b) { cout << a + b << endl; };            //error Plus不明确

auto addPlus = [v1 = 1, v2 = 2](int x, int y) -> double{
    return x + y + v1 + v2;
};

int main(int argc, char *argv[]) {
    int a = 15, b = 15;
    cout << add(a, b) << endl;
    cout << addPlus(a, b) << endl;

    //auto plus = [](int a, int b) { cout << a + b << endl; };
    //auto loggedPlus = wrapLog(plus);                                                
    auto loggedPlus = wrapLog(static_cast<std::function<void(int, int)>>(plus));

    return 0;
}

关注 2 回答 1

jeff_ 赞了回答 · 2019-09-30

解决关于linux中pause()函数的疑问

这里的pause捕获到信号为什么没有直接终止进程?
  1. “信号”会唤醒“挂起”状态的线程,但不能理解成 pause() 可以捕获信号。
  2. 两个例子区别在于,第一个进程没有被唤醒,而第二个进程被唤醒了。
  3. 为什么第一个进程没有被唤醒? 因为你没有重写 SIGALRM 信号的处理函数,默认情况下,该函数不会返回,它会终止进程,因此 pause() 后面的代码没有机会执行。
  4. 为什么第二个进程被唤醒? 因为你重写了 SIGALRM 信号的处理函数,并且该函数返回了,连带触发 pause()返回,进而执行后续代码。

参考资料

关注 4 回答 3