Const限定符和前向引用

RaG*_*__M 7 c++ templates c++11 c++14

seastar框架中看到过这段代码

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));
}
Run Code Online (Sandbox Code Playgroud)

using scheduling_group = int; auto current_scheduling_group(){ return int{};}//为了简单起见

让我们假设我将实例化task如下

 auto work = [](){...}
 make_task(work);
Run Code Online (Sandbox Code Playgroud)

如此以来,worklvalue make_task(Func&&)- > make_task(Func&)并将其实例lambda_tasklambda_task<Func&>引起这两个构建函数

lambda_task(scheduling_group sg, const Func& func)
lambda_task(scheduling_group sg, Func&& func)
Run Code Online (Sandbox Code Playgroud)

成为(我认为它会)

lambda_task(scheduling_group sg, **const Func& func**)
lambda_task(scheduling_group sg, **Func& func**)
Run Code Online (Sandbox Code Playgroud)

lambda_taskwith work对象的实例化会引发编译时错误

<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]'
Run Code Online (Sandbox Code Playgroud)

我做了什么让它发挥作用是我改变了

lambda_task(scheduling_group sg, Func&& func) to
lambda_task(scheduling_group sg, std::remove_reference_t<Func>&& func)
Run Code Online (Sandbox Code Playgroud)

问题1:我是对还是错?我的改变会破坏什么吗?还是需要它?

我意识到了

 lambda_task(scheduling_group sg, const Func& func)#1
 lambda_task(scheduling_group sg, Func && func)#2
Run Code Online (Sandbox Code Playgroud)

#1 & #2是冲突的,而且添加&&Func没有使它像rvalue引用折叠到lvalue(所以我使用std :: remove_reference_t)

问题2:假设T&&是一个前向引用[T = int]并折叠成T&.为什么std::is_same<const int&, const T&>不是真的?

<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,"");
Run Code Online (Sandbox Code Playgroud)

为什么添加const到折叠参考不会产生任何影响?

或者我的观察错了?

Jar*_*d42 8

对于template <typename T> class lambda_tasklambda_task<F&>我们有

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

你可能想要T分别腐朽const F&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)) {}
Run Code Online (Sandbox Code Playgroud)

  • @Aldarrion:例如,参见[reference_collapsing](https://www.ibm.com/support/knowledgecenter/SSGH3R_13.1.3/com.ibm.xlcpp1313.aix.doc/language_ref/reference_collapsing.html). (2认同)
  • @Aldarrion让我们使用East const使其更容易理解:`const T&` - always const - >`T const&`.现在我们替换F&:`T const&` - 取代F&for T - >`F&const&`.用简单的话来说:它引用了对F的const引用.但引用本身总是const,所以我们可以省略:`F &&`.现在它是对F的引用的引用,对引用的引用只是一个参考.所以它只是'F&`.总的来说,由Jarod42链接的表格具有所有细节,只是没有解释. (2认同)