提问人:glades 提问时间:12/16/2022 最后编辑:glades 更新时间:12/18/2022 访问量:338
“模板化 rvalue-reference”而不是通用引用作为参数?
"Templated rvalue-reference" instead of universal reference as parameter?
问:
我有一个类对象,它接受通用参数,这些参数被限制为某个概念。现在我想将此参数(哪种类型仍然未知)转发到适合此引用类型的重载:根据转发的参数选择 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!
更新:
由于上面的案例可能已经太做作了,无法真正展示我正在尝试的内容,你可以在这里找到一个更详细的例子。
答:
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 无需创建新主题,我在原始问题:)中附上了一个更详细示例的注释是的,我很高兴得到反馈。
评论
auto construct(const Cb&)
->auto construct(Cb&)
?auto construct(Cb&&) requires(std::is_rvalue_reference_v<Cb&&>)
??function{std::as_const(foo1)}