Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Const qualifier and forward reference

Have seen this code in the seastar framework

template <typename Func>
class lambda_task final : public task {
    Func _func;
public:
    lambda_task(scheduling_group sg, const Func& func) : task(sg), 
    _func(func) {}
    lambda_task(scheduling_group sg, Func&& func) : task(sg), 
    _func(std::move(func)) {}
    virtual void run_and_dispose() noexcept override {
        _func();
        delete this;
    }
};

template <typename Func>
inline std::unique_ptr<task> make_task(Func&& func) {
    return std::make_unique<lambda_task<Func>>(current_scheduling_group(), 
    std::forward<Func>(func));
}

using scheduling_group = int; auto current_scheduling_group(){ return int{};}//for simplicity

let us assume I am going to instantiate task like below

 auto work = [](){...}
 make_task(work);

so since the work is an lvalue make_task(Func&&)->make_task(Func&) and it instantiate lambda_task as lambda_task<Func&> which causes these two ctors

lambda_task(scheduling_group sg, const Func& func)
lambda_task(scheduling_group sg, Func&& func)

to become(I assume it would)

lambda_task(scheduling_group sg, **const Func& func**)
lambda_task(scheduling_group sg, **Func& func**)

the instantiation of lambda_task with work object is throwing a compile-time error

<source>:127:5: error: 'lambda_task<Func>::lambda_task(scheduling_group, Func&&) [with Func = main()::<lambda()>&; scheduling_group = int]' 
cannot be overloaded with 'lambda_task<Func>::lambda_task(scheduling_group, const Func&) [with Func = main()::<lambda()>&; scheduling_group = int]'

     lambda_task(scheduling_group sg, Func&& func) : task(sg), _func(std::move(func)) {}

     ^~~~~~~~~~~
<source>:126:5: note: previous declaration 'lambda_task<Func>::lambda_task(scheduling_group, const Func&) 
[with Func = main()::<lambda()>&; scheduling_group = int]'

and what I did to make it work is I've changed

lambda_task(scheduling_group sg, Func&& func) to
lambda_task(scheduling_group sg, std::remove_reference_t<Func>&& func)

question 1: was I right or wrong? will my change break anything? or it is needed?

I realized that the

 lambda_task(scheduling_group sg, const Func& func)#1
 lambda_task(scheduling_group sg, Func && func)#2

#1 & #2 is conflicting and moreover adding &&to Func doesn't make it as an rvalue as it was reference collapsed to lvalue(so I used std::remove_reference_t )

question 2: assume T&& is a forward reference [T=int] and collapsed into T&. why std::is_same<const int&, const T&> isn't true?

<source>:162:5:   required from 'void maketest(T&&) [with T = int&]'
<source>:154:18: error: static assertion failed
static_assert(std::is_same<const int&,const T&>::value,"");

why adding const to a collapsed reference isn't taking any effect?

or my observation is wrong?

like image 422
RaGa__M Avatar asked Jul 25 '18 13:07

RaGa__M


1 Answers

for template <typename T> class lambda_task, with lambda_task<F&>, we have

  • const T& = T const& = F&
  • and T&& = F&.

You probably want to decay both T to have respectively const F& and F&&:

lambda_task(scheduling_group sg, const std::decay_t<Func>& func) : task(sg), _func(func) {}

lambda_task(scheduling_group sg, std::decay_t<Func>&& func) : task(sg), _func(std::move(func)) {}
like image 126
Jarod42 Avatar answered Nov 11 '22 14:11

Jarod42