目前我的课程定义与此相似:
class dummy{
public:
dummy(void(&func)(int))
: member{func}{}
void(&member)(int);
};
但我想将member
定义为const
函数引用。我不确定如何写这个或者是否可能。
P.S。请不要推荐我std::function
我没有忘记它的存在并且不反对它,我只是想知道这样的事情是否可行。
答案 0 :(得分:2)
语法:
从语法上讲,您可以通过类型别名(或typedef
)实现此目的:
using function_t = void(int); // or typedef void (function_t)(int);
class dummy {
public:
const function_t& member;
dummy(const function_t& func)
: member{func}{}
};
语义:
但是,“正确的语法”并不能为您带来任何好处:dummy
与
class dummy {
public:
function_t& member;
dummy(function_t& func)
: member{func}{}
};
(反过来与OP的定义相同)因为根据C ++ 11 8.3.5 / 6忽略const
限定符:
cv-qualifier-seq在函数声明符中的作用与在函数类型之上添加cv-qualification不同。 在后一种情况下,忽略cv限定符。 [注意:具有cv-qualifier-seq的函数类型不是cv限定类型; 没有符合cv标准的函数类型。 - 后注]
rvalues怎么样?
据我所知(从评论到user657267的answer),将参数作为对const
的引用的动机是为了能够传递rvalues(临时值):< / p>
void f(int) { }
function_t make_function() { return f; }
dummy d1(f);
dummy d2(make_function());
但是,这不会编译,不是因为dummy
,而是因为make_function
返回的函数是C ++ 11 8.3.5 / 8
如果参数的类型包含“指向未知范围
T
的数组的指针”或“引用T
未知范围的数组”的类型,则该程序生效形成。 99 函数不应具有类型数组或函数的返回类型,尽管它们可能具有类型指针的返回类型或对此类事物的引用。虽然可以有函数指针数组,但是不应该有函数数组。
一个自然的“解决方案”将返回一个参考:
function& make_function() { return f; }
或
function&& make_function() { return f; }
在这两种情况下,表达式make_function()
的类型都是左值(根据C ++ 11,它使用dummy
引用const
来违反make_function
的目的,以启用传递rvalues) 5.2.2 / 10
如果结果类型是左值引用类型或函数类型的右值引用,则函数调用是左值,如果结果类型是对象类型的右值引用,则为xvalue,以及prvalue否则。
实际上,价值类别不是问题。任何dummy
的法律声明以及d1
的任何定义似乎都高于d2
和dummy d3([](int){}); // Error!
的声明。
尽管如此,所提到的对user657267的answer的评论谈到了传递lambda但是对函数的引用不能绑定到lambda表达式,因为它有不同的类型:
using function_t = void(int); // or typedef void (function_t)(int);
class dummy {
public:
function_t* member;
dummy(function_t* func)
: member{func}{}
};
void f(int) { }
function_t& make_function() { return f; }
dummy d1(f); // OK
dummy d2(make_function()); // OK
dummy d3([](int){}); // OK
建议的解决方案
而不是引用使用指针:
const function_t* member
最后的评论:
同样,声明dummy(const function_t* func)
和const
并不能为您带来任何好处,因为根据参考资料,d1
限定符会被忽略。
d2
和dummy
的初始化有效,因为函数被隐式转换为函数指针(参见C ++ 4.3 / 1)。
如果函数参数是函数类型,则编译器将其类型更改为指向函数的指针。因此,dummy(function_t func);
的构造函数可以声明为d3
。
{{1}}的初始化有效,因为无捕获的lambdas被隐式转换为指向函数的指针。对于带有捕获的lambda来说它不起作用。