“模板化 rvalue-reference”而不是通用引用作为参数?

"Templated rvalue-reference" instead of universal reference as parameter?

提问人:glades 提问时间:12/16/2022 最后编辑:glades 更新时间:12/18/2022 访问量:338

问:

我有一个类对象,它接受通用参数,这些参数被限制为某个概念。现在我想将此参数(哪种类型仍然未知)转发到适合此引用类型的重载:根据转发的参数选择 rvalue-ref 重载或 const ref 重载。我怎样才能做到这一点?construct

问题是,一旦我输入双 & 号,“模板化右值引用”就变成了一个通用引用,我看不出有什么方法可以规避它。下面的示例表明,在这两种情况下,都选择了“贪婪”的通用 ref 重载,即使我希望第一个实例化与 const ref 一起使用。

演示

#include <concepts>
#include <cstdio>
#include <utility>

template <typename... Args>
struct function
{
    template <std::invocable<Args...> Cb>
    function(Cb&& fn) {
        construct(std::forward<Cb>(fn));
    }

    template<typename Cb>
    auto construct(const Cb&) {
        printf("Overload for const-ref called!\n");
    }

    template <typename Cb>
    auto construct(Cb&&) {
        printf("Overload for rvalue-ref called!\n");
    }
};

struct functor
{
    auto operator()()
    {
        printf("Functor called!\n");
    }
};

int main()
{
    functor foo1;

    function myfunc{foo1};
    function myfunc2{functor{}};
}

输出:

Overload for rvalue-ref called!
Overload for rvalue-ref called!

更新

由于上面的案例可能已经太做作了,无法真正展示我正在尝试的内容,你可以在这里找到一个更详细的例子。

C++ 模板 重载 forwarding-reference

评论

1赞 NathanOliver 12/16/2022
auto construct(const Cb&) -> auto construct(Cb&)?
3赞 n. m. could be an AI 12/16/2022
auto construct(Cb&&) requires(std::is_rvalue_reference_v<Cb&&>)??
0赞 Jarod42 12/16/2022
@NathanOliver:然后会选择错误的过载;-)function{std::as_const(foo1)}
0赞 glades 12/16/2022
@n我需要 requires 子句中的 && 做什么?为了不折叠引用?
1赞 StoryTeller - Unslander Monica 12/16/2022
stackoverflow.com/a/46214158/817643

答:

3赞 Brian Bi 12/17/2022 #1

主要答案是,您应该尽量不要这样做,因为通常没有充分的理由来执行这种过载解决。当你有一个具体类型时,有一个接受左值引用的重载和一个接受右值引用的重载是有意义的,因为只有后者有权从其参数中掠夺资源。但是,如果函数模板说“我接受任何东西,但它必须过期”,通常不能对其参数即将过期的信息做任何有用的事情,除非最终将其转发给采用具体类型的重载。

但是,这是可能的。一种方法是:

template <typename Cb>
auto construct(Cb&&) requires(!std::is_reference_v<Cb>) {
    printf("Overload for rvalue-ref called!\n");
}

这使用这样一个事实,即如果转发引用的参数是左值,则模板参数被推导为左值引用,但如果参数是右值,则模板参数被推导为引用类型(即非引用)。

评论

0赞 glades 12/17/2022
在 3+ 年的编码 C++ 中,我也从未偶然遇到过这种情况,但在这种情况下,恕我直言,这是有道理的,因为参数通过类型擦除的函数指针转发给分配器构造器(),并且新对象应该移动或复制构造。无论如何,“非参考”是什么意思?只是左值?
1赞 sigma 12/17/2022
@glades 在这种情况下,它被推断为只是 Cb。因此,您还可以将 .这似乎有悖常理,但左值版本(Cb&)&&折叠为Cb&,并且无法通过此测试。std::is_rvalue_reference_v<Cb&&>
0赞 glades 12/17/2022
@sigma完美,谢谢。这似乎比 std::is_reference 更容易争论,并且可能应该包含在答案中。
0赞 Brian Bi 12/18/2022
@glades 如果你发布另一个问题,其中包含显示你的用例的代码,我可能会向你解释为什么你不需要有一个通用的右值特定的重载。
0赞 glades 12/18/2022
@BrianBi 无需创建新主题,我在原始问题:)中附上了一个更详细示例的注释是的,我很高兴得到反馈。