具有右值引用,而不是使用可变参数模板转发引用

博洛夫

我有一个结构X和函数foo,必须接收的右值引用X

最初,我仅以一个参数开始,这很简单(哦,更简单的时间):

auto foo(X&& arg) -> void {...};

X x;
foo(x);            // compile error [OK]
foo(std::move(x)); // accepted      [OK]
foo(X{});          // accepted      [OK]

但是后来我想扩展并接受可变数量的X参数(仍然仅是右值引用)。

但有一个问题。

  • 第一,你不可能拥有auto foo(X&&... args)理想的
  • 2nd现在您被迫这样做,template <class... Args> auto foo(Args&&... args)但最终您将获得转发引用,该引用将很乐意接受非临时人员:
template <class... Args>
auto foo(Args&&... args) -> void { ... };

X x1, x2;
foo(x1, x2);                       // accepted [NOT OK]
foo(std::move(x1), std::move(x2)); // accepted [OK]
foo(X{}, X{});                     // accepted [OK]

自从乞讨以来,为什么他们使用这种语法和规则转发参考。这是一个问题。这种语法的另一个问题是T&&X<T>&&是完全不同的野兽。但是我们在这里偏离了轨道。

我知道如何用来解决该问题,static_assert或者SFINAE这两种解决方案都会使事情复杂化,而且我谦虚地认为,如果该语言只设计一次,就永远不需要。甚至不要让我开始std::initializer_list……我们又偏离了轨道。

所以我的问题是:有没有一个简单的解决方案/技巧,我被女巫所缺少Args&&/args被当作​​右值引用?


当我总结这个问题时,我以为我有一个解决方案。

为左值引用添加已删除的重载:

template <class... Args>
auto foo(const Args&... args) = delete;

template <class... Args>
auto foo(Args&... args) = delete;

简单,优雅,应该可以工作,让我们对其进行测试:

X x1, x2;

foo(x1, x2);                       // compile error [OK]
foo(std::move(x1), std::move(x2)); // accepted [OK]
foo(X{}, X{});                     // accepted [OK]

好吧,是的,我有!

foo(std::move(x1), x2);            // accepted [oh c'mon]
巴里

有一堆右值引用的方法是用SFINAE:

template <class... Args,
    std::enable_if_t<(!std::is_lvalue_reference<Args>::value && ...), int> = 0>
void foo(Args&&... args) { ... }

折叠表达式是C ++ 17,编写一个元函数很容易在C ++ 14中获得相同的行为。这确实是您唯一的选择-您想要一个约束函数模板来推导右值引用,但是唯一可用的语法已重载以表示转发引用。我们可以使模板参数不被推导,但是随后您必须提供它们,这似乎根本不是解决方案。

使用概念,这当然更清洁,但是我们并没有真正改变底层的机制:

template <class... Args>
    requires (!std::is_lvalue_reference<Args>::value && ...)
void foo(Args&&... args) { ... }

或更好:

template <class T>
concept NonReference = !std::is_lvalue_reference<T>::value;

template <NonReference... Args>
void foo(Args&&... ) { ... }

值得指出的是,这些都不起作用:

template <class... Args> auto foo(const Args&... args) = delete;
template <class... Args> auto foo(Args&... args) = delete;

因为它们仅删除采用所有左值引用的重载,而您要删除采用任何左值引用的重载

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

在可变参数模板中使用std :: bind完美转发引用

具有const引用的可变参数模板

根据函数签名将可变参数模板中的类型转发为值/引用

具有转发引用的静态多态

模板代码中的转发引用与const左值引用

具有左值和右值的可变参数模板类构造函数

转发模板参数的一致性,是否应该使用转发引用?

具有递归继承并使用声明的可变参数模板

转发引用和参数推导

可变参数模板参数:我可以根据类型选择引用还是值?

可变参数模板函数参数和引用类型推导

转发引用不是被推导为 r 值引用吗?

类模板与函数模板中的右值引用

完美转发可变参数模板模板

如何使用参数中的不匹配引用修饰符动态播送可变参数模板?

具有模板函数名称的可变参数模板

具有可变参数模板参数的函数指针

在C ++ 17中使用转发引用时,模板结构是否需要std :: decay?

可以使用别名模板为转发引用添加别名吗?

使用std :: function或转发引用作为高阶函数的通用可调用对象输入参数?

具有双打的C ++可变参数模板

C ++创建具有可变参数模板方法的接口

具有可变参数模板的成员函数指针

具有元组的C ++可变参数模板

如何具有类型和大小的可变参数模板?

具有模板函数名称,传递参数和周围返回值的可变参数模板

使用sfinae检测可变参数模板的基类是否具有特定方法

在带有可变参数模板的基于模板的类中进行完善转发?

使用一参数模板化构造函数从引用元组构造值元组