鉴于此代码,模板参数推导如何决定如何为最后一个函数调用做什么?
#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.我的目标是创建一个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) 考虑以下程序:
#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++]
这通常没问题,除了这个例子的几个东西:
如果我注释掉任何构造函数,指针声明或字符串声明,警告就会消失.这很奇怪,因为你认为指针就足够了,但事实并非如此.此外,将字符串声明更改为整数声明也会导致它消失,因此只有在有字符串(或可能是其他选择类)时才会出现.为什么在这种情况下警告会消失?
通常,当所有指针都在指向现有变量(通常由OS维护)时,会出现此警告.没有new,没有delete.当复制带有句柄的类时,我不想要深层复制.我希望两个句柄指向同一个内部对象(例如窗口).有没有办法让编译器实现这一点,而不会不必要地重载复制构造函数和赋值运算符,或完全禁用警告#pragma?当三法则甚至不适用时,为什么我首先被困扰?
我最近遇到了这段代码
T operator () () &
{
...
}
T operator () () &&
{
...
}
Run Code Online (Sandbox Code Playgroud)
而且我很困惑.&和&&在这种情况下意味着什么?这类似于复制和移动构造函数,但是对于函数?
我正在尝试包装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函数:
void foo(int(__stdcall *callback)());
Run Code Online (Sandbox Code Playgroud)
C函数指针回调的两个主要缺陷是:
我想知道包装这些函数的最佳方法.第一个对于成员函数回调特别有用,第二个对于使用周围变量的内联定义特别有用,但这些不是唯一用途.
这些特定函数指针的另一个属性是它们需要使用__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) 受这个问题的启发,询问如何将一个向量附加到自身,我的第一个想法是以下(是的,我意识到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.
在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定义好的?这种未定义的行为是什么?
我正在编码并意外地在常量引用和默认值之间留下了空格.我很惊讶地看到它在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上编译都很好,这意味着&=并不总是作为运算符进行词法配对.
为什么它适用于右值参考,而不是左值参考,标准对此有何看法?
我正在尝试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)