我有下面的程序:
#include<type_traits>
#include<iostream>
using namespace std;
template <class F, class R = typename result_of<F()>::type>
R call(F& f) { return f(); }
struct S {
double operator()(){return 0.0;}
};
int f(){return 1;}
int main()
{
S obj;
call(obj);//ok
call(f);//error!
return 0;
}
在"call(f)"行编译失败。奇怪的是"call(obj)"是OK的
(1)我有一个类似的帖子在另一个线程c++ 11的结果推断我的函数类型失败。但是它并没有说明为什么函数函数对象可以,而函数对象不行。
(2)我不确定这是否与"R call(F&f):函数类型不能声明l值?
(3)只要我知道,任何有名字的标记,比如变量/函数,都应该被认为是l值。在函数参数的情况下,编译器应该"衰减"我的函数名"f"到一个函数指针,对吗?
(4)这就像衰减一个数组并将其传递给一个函数----函数指针可以是一个l值,那么"call(F&f)"?
你能帮我进一步解释一下"为什么"是我的情况吗,我哪里错了?谢谢。
call(f)
的问题是您将F
推断为函数类型,因此它不会衰减为函数指针。相反,你得到一个函数的引用。那么result_of<F()>
表达式是无效的,因为F()
是int()()
,即返回一个函数的函数,而这个函数在c++中不是有效的类型(函数可以返回指向函数的指针或对函数的引用,但不是函数)。
如果你使用result_of<F&()>
,它将工作,这是更准确的,因为你是如何调用可调用对象。在call(F& f)
中执行f()
,并且在该上下文中f
是左值,因此您应该询问调用没有参数的左值F
的结果是什么,否则您可能会得到错误的答案。考虑:
struct S {
double operator()()& {return 0.0;}
void operator()()&& { }
};
现在result_of<F()>::type
是void
,这不是你想要的答案。
如果你使用result_of<F&()>
然后你得到正确的答案,当F
是一个函数类型时,它也有效,所以call(f)
也有效。
(3)只要我知道,任何有名字的标记,比如变量/函数,都应该被认为是l值。在函数参数的情况下,编译器应该"衰减"我的函数名"f"到一个函数指针,对吗?
不,见上文。你的call(F&)
函数通过引用接受它的参数,所以没有衰减。
(4)这就像衰减一个数组并将其传递给一个函数----函数指针可以是一个l值,那么"call(F&f)"?
数组在通过引用传递时也不会衰减。
如果你想让参数衰减,那么你应该写call(F f)
而不是call(F& f)
。但是,即使您这样做,您仍然需要正确使用result_of
来获得f()
的结果,其中f
是左值。