小编chr*_*ris的帖子

在这种情况下,模板参数推导如何工作?

鉴于此代码,模板参数推导如何决定如何为最后一个函数调用做什么?

#include <iostream>

template<typename Ret, typename... Args>
Ret foo(Args&&...) {
    std::cout << "not void\n";
    return {};
}

template<typename... Args>
void foo(Args&&...) {
    std::cout << "void\n";
}

int main() {
    foo(3, 'a', 5.4);            //(1): prints "void"
    foo<int, char>(3, 'a', 5.4); //(2): prints "void"
    foo<int>('a', 5.4);          //(3): prints "not void"
    foo<int>(3, 'a', 5.4);       //(4): prints "not void"
}
Run Code Online (Sandbox Code Playgroud)

(1)看起来很简单.它不能推断出返回类型,因此使用了void版本.

(2)明确陈述一些参数的类型.第一个模板参数匹配第一个参数,第二个模板参数匹配第二个参数,推导出第三个模板参数.如果int用于返回类型,则char与第一个参数不匹配.

(3)与(2)做同样的事情,但第一种类型不匹配.因此,必须将其推断为返回类型和用于推导两个Args参数的两个参数.

(4)似乎含糊不清.它显式指定了模板参数,就像(2)和(3)一样.模板参数与参数匹配,就像(2)一样.但是,它不使用它作为第一个并推导出其他两个,而是使用显式模板参数作为返回类型并推导出所有三个Args参数.


为什么(4)似乎有一半跟随(2),但是然后使用其他版本?我最好的猜测是填充的单个模板参数是一个比参数包更好的匹配.标准在哪里定义了这种行为?

这是使用GCC 4.8.0编译的.为方便起见,这是对Coliru测试.

但是,在Clang 3.1中,(4)由于含糊不清(见注释)而无法编译.这开启了这两个编译器中的一个有错误的可能性.使这种可能性更可能的是,Visual Studio …

c++ templates variadic-templates c++11

16
推荐指数
1
解决办法
522
查看次数

C free():指针无效

我正在自学C.我的目标是创建一个C函数,它只是遍历一个查询字符串并在&符号和等号上分开.我对Valgrind的这个错误感到困惑.

==5411== Invalid free() / delete / delete[] / realloc()
==5411==    at 0x402AC38: free (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5411==    by 0x804857C: main (leak.c:28)
==5411==  Address 0x420a02a is 2 bytes inside a block of size 8 free'd
==5411==    at 0x402AC38: free (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5411==    by 0x804857C: main (leak.c:28)
==5411== 
==5411== 
==5411== HEAP SUMMARY:
==5411==     in use at exit: 0 bytes in 0 blocks
==5411==   total heap usage: 1 allocs, 2 frees, 8 bytes allocated
==5411== 
==5411== All heap blocks were freed -- no …
Run Code Online (Sandbox Code Playgroud)

c free valgrind pointers

16
推荐指数
2
解决办法
9万
查看次数

理解-Weffc ++

考虑以下程序:

#include <string>

struct S {
    S (){}

private:
    void *ptr = nullptr;
    std::string str = "";
};

int main(){}
Run Code Online (Sandbox Code Playgroud)

在使用-Weffc++GCC 4.7.1 编译时,这将吐出:

warning: 'struct S' has pointer data members [-Weffc++]
warning:   but does not override 'S(const S&)' [-Weffc++]
warning:   or 'operator=(const S&)' [-Weffc++]

这通常没问题,除了这个例子的几个东西:

  1. 如果我注释掉任何构造函数,指针声明或字符串声明,警告就会消失.这很奇怪,因为你认为指针就足够了,但事实并非如此.此外,将字符串声明更改为整数声明也会导致它消失,因此只有在有字符串(或可能是其他选择类)时才会出现.为什么在这种情况下警告会消失?

  2. 通常,当所有指针都在指向现有变量(通常由OS维护)时,会出现此警告.没有new,没有delete.当复制带有句柄的类时,我不想要深层复制.我希望两个句柄指向同一个内部对象(例如窗口).有没有办法让编译器实现这一点,而不会不必要地重载复制构造函数和赋值运算符,或完全禁用警告#pragma?当三法则甚至不适用时,为什么我首先被困扰?

c++ pointers g++ compiler-warnings rule-of-three

14
推荐指数
2
解决办法
2万
查看次数

功能声明后的&符号

我最近遇到了这段代码

T operator () () &
{
...
}

T operator () () &&
{
...
}
Run Code Online (Sandbox Code Playgroud)

而且我很困惑.&和&&在这种情况下意味着什么?这类似于复制和移动构造函数,但是对于函数?

c++ c++11

13
推荐指数
0
解决办法
202
查看次数

如果Template Argument无效,请在Compile-Time检查

我正在尝试包装Windows API函数以在我选择时检查错误.正如我在之前的SO问题中发现的那样,我可以使用模板函数来调用API函数,然后调用GetLastError()以检索它可能设置的任何错误.然后,我可以将此错误传递给我的Error班级让我知道.

这是模板函数的代码:

template<typename TRet, typename... TArgs>
TRet Wrap(TRet(WINAPI *api)(TArgs...), TArgs... args)
{
    TRet ret = api(args...);
    //check for errors
    return ret;
}
Run Code Online (Sandbox Code Playgroud)

使用这个我可以有如下代码

int WINAPI someFunc (int param1, BOOL param2); //body not accessible

int main()
{
    int ret = someFunc (5, true); //works normally
    int ret2 = Wrap (someFunc, 5, true); //same as above, but I'll get a message if there's an error
}
Run Code Online (Sandbox Code Playgroud)

这非常有效.但是,有一个可能的问题.采取这个功能

void WINAPI someFunc();
Run Code Online (Sandbox Code Playgroud)

将其转换为模板函数时,它看起来如下:

void Wrap(void(WINAPI *api)())
{
    void ret …
Run Code Online (Sandbox Code Playgroud)

c++ typechecking compile-time variadic-templates c++11

12
推荐指数
1
解决办法
4355
查看次数

使用C++ 11接口包装C回调的最佳方法是什么?

假设这是一个要包装的C函数:

void foo(int(__stdcall *callback)());
Run Code Online (Sandbox Code Playgroud)

C函数指针回调的两个主要缺陷是:

  • 无法存储绑定表达式
  • 无法存储捕获lambda

我想知道包装这些函数的最佳方法.第一个对于成员函数回调特别有用,第二个对于使用周围变量的内联定义特别有用,但这些不是唯一用途.

这些特定函数指针的另一个属性是它们需要使用__stdcall调用约定.据我所知,这完全取消了lambda作为一种选择,否则会有点麻烦.我想至少__cdecl也允许这样做.

这是我能够提出的最好的东西,没有东西开始回归依赖于函数指针所没有的支持.它通常在标题中.以下是Coliru的示例.

#include <functional>

//C function in another header I have no control over
extern "C" void foo(int(__stdcall *callback)()) {
    callback();
}

namespace detail {
    std::function<int()> callback; //pretend extern and defined in cpp

    //compatible with the API, but passes work to above variable
    extern "C" int __stdcall proxyCallback() { //pretend defined in cpp
        //possible additional processing
        return callback();
    }
}

template<typename F> //takes anything
void wrappedFoo(F …
Run Code Online (Sandbox Code Playgroud)

c++ lambda callback stdbind c++11

12
推荐指数
2
解决办法
3453
查看次数

使用copy和back_inserter将向量附加到自身时出现错误的结果

这个问题的启发,询问如何将一个向量附加到自身,我的第一个想法是以下(是的,我意识到insert现在是一个更好的选择):

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

int main() {
    std::vector<int> vec {1, 2, 3};
    std::copy (std::begin (vec), std::end (vec), std::back_inserter (vec));

    for (const auto &v : vec)
        std::cout << v << ' ';
}
Run Code Online (Sandbox Code Playgroud)

但是,这打印:

1 2 3 1 * 3
Run Code Online (Sandbox Code Playgroud)

每次运行程序时*都是不同的数字.只有2被替换的事实是特殊的,如果真的有解释,我会有兴趣听到它.继续,如果我附加到不同的向量(原始副本),它会正确输出.如果我在前一行之前添加以下行,它也会正确输出copy:

vec.reserve (2 * vec.size());
Run Code Online (Sandbox Code Playgroud)

std::back_inserter尽管事先没有预留内存,但我认为这是一种将元素添加到容器末端的安全方法.如果我的理解是正确的,复制线有什么问题?

我假设它与编译器无关,但我使用的是GCC 4.7.1.

c++ iterator stl undefined-behavior stl-algorithm

11
推荐指数
1
解决办法
1347
查看次数

在main之前退出程序是明确定义的行为吗?

main调用之前执行代码绝对是可能的,正如本问题中的许多示例所示.

但是,如果在该主要代码之前,程序被告知通过std::exit或退出std::abort?既然main被定义为程序的开始,那么在开始之前退出会产生什么后果?

在每个部分打印一些东西后,我得到以下结果:

格式:
部分:output

Main:main
Init(在main之前调用):init
Exit(std::atexit在Init内部设置):exiting



样品运行:

在不退出的情况下调用Init:

init
main
返回0

Init调用std :: exit(0):

init
返回0

Init调用std :: abort:

init
崩溃并在Windows上返回3,GCC 4.7.2
崩溃,并在LiveWorkSpace上显示VS11 返回0 的常用框

Init设置处理程序并调用std :: exit(0):

init
退出
返回0

Init设置处理程序并调用std :: abort:

如果没有处理程序,初始化
相同

在搜索时,我看到了这样一个问题:在main()之前,C/C++程序有什么方法可以崩溃吗?.但是,它没有回答我想知道的事情:这种行为是在调用之前std::exit还是std::abort以前main定义好的?这种未定义的行为是什么?

c++ program-entry-point exit undefined-behavior

11
推荐指数
1
解决办法
300
查看次数

必须&=始终被解释为运营商?

我正在编码并意外地在常量引用和默认值之间留下了空格.我很惊讶地看到它在Intellisense中出现错误,所以我编译了它,当然,它在GCC 4.3.4,4.5.1或4.7.2中不起作用,并且不起作用Visual Studio 2012也是.

这是一个演示错误的等效示例:

struct S {
    S(const int &= 5){}    
};

int main(){}
Run Code Online (Sandbox Code Playgroud)

这会在GCC中产生以下错误,并在MSVC中产生类似的错误:

错误:在'&='标记之前预期','或'...'

我认为这是因为&=被视为操作员,但我不知道在标准中搜索的确切内容以查找有关此案例的更多信息.&=只提供运营商特定的信息.

好奇,我决定把它换成右值参考:

S(int &&= 5){}
Run Code Online (Sandbox Code Playgroud)

奇怪的是,这在GCC 4.7.2和MSVC上编译都很好,这意味着&=并不总是作为运算符进行词法配对.

为什么它适用于右值参考,而不是左值参考,标准对此有何看法?

c++ reference lexical-analysis language-lawyer

11
推荐指数
2
解决办法
223
查看次数

使用std :: bind时从std :: function获取函数指针

我正在尝试std::function与之配合使用std::bind,但我遇到了一些问题.

这有效:

#include <functional>
#include <iostream>

void print() {
    std::cout << 2;
}

int main() {
    std::function<void ()> foo = print;
    (*foo.target<void (*)()>())(); //prints 3
}
Run Code Online (Sandbox Code Playgroud)

这崩溃在第二行main:

#include <functional>
#include <iostream>

void print (int i) {
    std::cout << i;
}

int main() {
    std::function<void ()> foo = std::bind (print, 2);
    (*foo.target<void (*)()>())();
}
Run Code Online (Sandbox Code Playgroud)

我真的抱着std::function<void ()>并且需要能够返回功能; 不只是打电话给它.我希望用法是这样的:

#include <functional>
#include <iostream>

void print (int i) {
    std::cout << i;
}

int main() { …
Run Code Online (Sandbox Code Playgroud)

c++ bind function-pointers c++11

10
推荐指数
3
解决办法
2万
查看次数