鉴于以下代码,模糊性背后的原因是什么?我可以绕过它还是我必须保持(讨厌的)显式演员?
#include <functional>
using namespace std;
int a(const function<int ()>& f)
{
return f();
}
int a(const function<int (int)>& f)
{
return f(0);
}
int x() { return 22; }
int y(int) { return 44; }
int main()
{
a(x); // Call is ambiguous.
a(y); // Call is ambiguous.
a((function<int ()>)x); // Works.
a((function<int (int)>)y); // Works.
return 0;
}
Run Code Online (Sandbox Code Playgroud)
有趣的是,如果我a()用function<int ()>参数注释掉函数并a(x)在我的main中调用,则编译正确失败,因为它们之间的类型不匹配x和function<int (int)>唯一a()可用函数的参数.如果编译器在这种情况下失败,为什么在存在这两个a()函数时会有任何歧义?
我试过VS2010和g ++ v.4.5.两者都给我完全相同的歧义.
所有报价均来自N3797.
4/3 [转]
当且仅当声明T t = e时,表达式e可以隐式转换为类型T. 对于一些发明的临时变量t而言,其形式良好
这意味着没有表达式可以隐式转换为void,这void t=e对所有表达式都是非法的e.如果e是类型的表达式void,例如,这甚至是真的void(3).
所以类型的表达式void不能隐式转换为void.
这导致我们:
20.9.2/2要求[func.require]
将INVOKE(f,t1,t2,...,tN,R)定义为隐式转换为R的INVOKE(f,t1,t2,...,tN).
总之,INVOKE(f, t1, t2, ..., tN, R)当是永远有效R的void,如无(含void)可以隐式转换为void.
因此,所有都std::function<void(Args...)>具有属性!*this,因此不能被调用,因为唯一没有!*this后置条件的构造函数(或者不从function相同类型的另一个复制此类状态)需要Callable其中一个参数.
20.9.11.2/7类模板函数[func.wrap.func]
要求:F应为CopyConstructible.对于参数类型ArgTypes,f应为Callable(20.9.11.2)并返回R类型.A的拷贝构造函数和析构函数不应抛出异常.
20.9.11.2/2类模板函数[func.wrap.func]
类型F的可调用对象f对于参数类型ArgTypes是Callable,如果表达式INVOKE(f,declval()...,R)被认为是未评估的操作数(第5条),则返回类型R( 20.9.2).
如上所述,没有Callable表达std::function<void(Args...)>.
如果以某种方式std::function<void(Args...)>找到这样的地方,调用operator()将会形成错误:
调用[func.wrap.func.inv]
效果:INVOKE(f,std :: forward(args)...,R)(20.9.2),其中f是*this的目标对象(20.9.1).
因为INVOKE(f, …
我最近惊讶于lambdas可以被分配给std::function具有略微不同签名的s .略有不同意味着当function指定返回时void,lambda的返回值可能会被忽略,或者参数可能是functionlambda 中的值但是引用.
请参阅此示例(ideone),其中我强调了我怀疑不兼容的内容.我认为返回值不是问题,因为你总是可以调用一个函数并忽略返回值,但是从引用到值的转换看起来很奇怪:
int main() {
function<void(const int& i)> f;
// ^^^^ ^^^^^ ^
f = [](int i) -> int { cout<<i<<endl; return i; };
// ^^^ ^^^^^^
f(2);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
小问题是:为什么这段代码编译和工作?主要问题是:与lambda参数和返回值一起使用时,类型转换的一般规则是什么std::function?
根据C++ 11或C++ 14标准,代码是否在有效的C++下面?
#include <functional>
int ReturnInt()
{
return 5;
}
int main( int argc, char **argv )
{
std::function< void () > BoundType = ReturnInt;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
该代码可以使用最新的gg(4.8.3)和clang(4.3.2)的cygwin版本编译,但不适用于Visual Studio 2013,Visual Studio 2013年11月的CTP或Visual Studio 14预览版.如果将std :: function更改为boost :: function,它也会在所有平台上编译.
我发现这个其他堆栈溢出问题表明它应该工作.
std::function 允许你这样做:
std::function<void()> = []()->int{return 42;};
Run Code Online (Sandbox Code Playgroud)
但不是这个:
std::function<void()> = [](int i)->int{return 42;};
Run Code Online (Sandbox Code Playgroud)
大概是因为返回类型不是函数签名的一部分.但是std::function是一个类类型,它被赋予一个返回类型,并且知道它构造的函数对象的返回类型.所以这里可能存在编译器错误.
为什么没有编译器错误?
我正在尝试模仿 std::thread 构造函数功能:
template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args );
Run Code Online (Sandbox Code Playgroud)
我试过使用调试器来查看它是如何工作的,但我无法弄清楚。
如何像线程的构造函数那样创建和存储绑定类型?
像这样(语法可能错误):
class myClass{
private:
auto bindType;
public:
template< class Function, class... Args >
explicit myClass( Function&& f, Args&&... args ) : bindType(somehowBind(f, args) {}
void evaluate() {bindType();}
};
Run Code Online (Sandbox Code Playgroud)
用法示例:
int test(int i) {return i;}
int main(){
myClass my(test, 5);
my.evaluate();
}
Run Code Online (Sandbox Code Playgroud)
请注意,我不在乎somehowBind函数是否会忽略返回类型,即它的返回类型可以是 std::function 之类的东西。我不想做的就是了解我如何绑定class... Args到给定的函数f,以便在调用后somehowBind它会像 std::bind 一样。为了澄清我的观点,您可以考虑我想要实现的目标如下:
thread t(test, 5); // unlike the usual …Run Code Online (Sandbox Code Playgroud) 如果 lambda 的返回类型不匹配,看起来我的 clang 编译器 (3.3) 不会生成任何错误:
#include <functional>
typedef std::function<void()> voidFunc;
void foo(voidFunc func)
{
func();
}
int main()
{
int i = 42;
foo([i]()
{
return i;
});
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译此代码不会显示任何错误:
clang++ -c -Xclang -stdlib=libc++ -std=c++11 -Weverything -Wno-c++98-compat -Wno-missing-prototypes -o foo.o foo.cpp
Run Code Online (Sandbox Code Playgroud)
如何针对此类问题生成类型错误?
编辑:
这会产生类型错误:
#include <functional>
struct A {};
struct B {};
typedef std::function<A()> aFunc;
void foo(aFunc func)
{
func();
}
int main()
{
int i = 42;
foo([i]()
{
return B();
});
return 0;
} …Run Code Online (Sandbox Code Playgroud)