如何编写常量函数引用

时间:2014-04-09 03:55:12

标签: c++ c++11 function-pointers

目前我的课程定义与此相似:

class dummy{
    public:
        dummy(void(&func)(int))
            : member{func}{}

        void(&member)(int);
};

但我想将member定义为const函数引用。我不确定如何写这个或者是否可能。

P.S。请不要推荐我std::function我没有忘记它的存在并且不反对它,我只是想知道这样的事情是否可行。

1 个答案:

答案 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怎么样?

据我所知(从评论到user657267answer),将参数作为对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的任何定义似乎都高于d2dummy d3([](int){}); // Error! 的声明。

尽管如此,所提到的对user657267answer的评论谈到了传递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

最后的评论:

  1. 同样,声明dummy(const function_t* func)const并不能为您带来任何好处,因为根据参考资料,d1限定符会被忽略。

  2. d2dummy的初始化有效,因为函数被隐式转换为函数指针(参见C ++ 4.3 / 1)。

  3. 如果函数参数是函数类型,则编译器将其类型更改为指向函数的指针。因此,dummy(function_t func);的构造函数可以声明为d3

  4. {{1}}的初始化有效,因为无捕获的lambdas被隐式转换为指向函数的指针。对于带有捕获的lambda来说它不起作用。