标签: forwarding-reference

身份别名模板可以作为转发参考吗?

请考虑以下以下代码段:

template <class T>
using identity = T;

template <class T>
void foo(identity<T>&&) {}

int main()
{
  int i{};
  foo(i);
}
Run Code Online (Sandbox Code Playgroud)

i是一个左值,因此如果foo声明一个转发引用参数,它应该编译.但是,如果identity<T>&&转为int&&,则应该引发错误.

该代码在GCC 6.0.0(演示)中编译.

代码无法在Clang 3.7.0(演示)中编译,并显示错误消息:

error: no known conversion from 'int' 
to 'identity<int> &&' (aka 'int &&') for 1st argument
Run Code Online (Sandbox Code Playgroud)

哪一个是对的?

c++ alias templates c++14 forwarding-reference

16
推荐指数
2
解决办法
399
查看次数

将文字作为const ref参数传递

想象一下以下简化代码:

#include <iostream>
void foo(const int& x) { do_something_with(x); }

int main() { foo(42); return 0; }
Run Code Online (Sandbox Code Playgroud)

(1)除了优化之外,42传递给什么时会发生什么foo

编译器是否在某处(在堆栈上?)并将其地址传递给foo

(1a)标准中是否有任何内容规定在这种情况下要做什么(或者它是否严格取决于编译器)?


现在,想象一下略有不同的代码

#include <iostream>
void foo(const int& x) { do_something_with(x); }

struct bar { static constexpr int baz = 42; };

int main() { foo(bar::baz); return 0; }
Run Code Online (Sandbox Code Playgroud)

它不会链接,除非我定义int bar::baz;(由于ODR?).

(2)除了ODR之外,为什么编译器不能对上面的42做什么呢?


简化事物的一种明显方法是定义foo为:

void foo(int x) { do_something_with(x); }
Run Code Online (Sandbox Code Playgroud)

但是,如果是模板,会怎么做?例如:

template<typename T>
void foo(T&& x) { do_something_with(std::forward<T>(x)); }
Run Code Online (Sandbox Code Playgroud)

(3)是否有一种优雅的方式来foo表示接受x原始类型的价值?或者我是否需要专注于SFINAE或其他一些?

编辑 …

c++ one-definition-rule c++11 pass-by-const-reference forwarding-reference

16
推荐指数
1
解决办法
1048
查看次数

为什么std :: forward返回static_cast <T &&>而不是static_cast <T>?

让我们有一个名为Y的函数重载:

void Y(int& lvalue)
{ cout << "lvalue!" << endl; }

void Y(int&& rvalue)
{ cout << "rvalue!" << endl; }
Run Code Online (Sandbox Code Playgroud)

现在,让我们定义一个像std :: forward一样的模板函数

template<class T>
void f(T&& x)
{
   Y( static_cast<T&&>(x) );   // Using static_cast<T&&>(x) like in std::forward
}
Run Code Online (Sandbox Code Playgroud)

现在看看main()

int main()
{
   int i = 10;

   f(i);       // lvalue >> T = int&
   f(10);      // rvalue >> T = int&&
}
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,输出是

lvalue!
rvalue!
Run Code Online (Sandbox Code Playgroud)

现在回到模板功能f()并替换static_cast<T&&>(x)static_cast<T>(x).让我们看看输出:

lvalue!
rvalue!
Run Code Online (Sandbox Code Playgroud)

一样的!为什么?如果它们是相同的,那么为什么std::forward<>从返回一个投x来 …

c++ rvalue static-cast c++11 forwarding-reference

15
推荐指数
1
解决办法
855
查看次数

结构化绑定和转发引用是否组合良好?

我知道我能做到

auto&& bla = something();
Run Code Online (Sandbox Code Playgroud)

并且根据const返回值的something不同,我会得到一个不同的类型bla.

这是否也适用于结构化绑定案例,例如

auto&& [bla, blabla] = something();
Run Code Online (Sandbox Code Playgroud)

我猜是这样的(结构化绑定捎带在auto初始化器上,表现得像这样),但我找不到肯定的肯定.

更新:初步测试似乎符合我的预期(const正确推导出来):

#include <tuple>

using thing = std::tuple<char, int*, short&, const double, const float&>;

int main()
{
    char c = 0;
    int i = 1;
    short s = 2;
    double d = 3.;
    float f = 4.f;

    thing t{c, &i, s, d, f};

    auto&& [cc, ii, ss, dd, ff] = t;

    c = 10;
    *ii = 11; …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer forwarding-reference c++17 structured-bindings

15
推荐指数
1
解决办法
365
查看次数

为什么对于左值,明确选择左值引用重载而不是转发引用重载?

看一下这两个重载的函数模板:

template <class T>
int foo(T& x) {  // #1
  return 1;
}
template <class T>
int foo(T&& x) {  // #2
  return 2;
}
Run Code Online (Sandbox Code Playgroud)

foo通过以下方式调用:

int i;
foo(i);  // calls #1
Run Code Online (Sandbox Code Playgroud)

并且明确选择了重载#1:https ://gcc.godbolt.org/z/zchK1zxMW

这似乎是一个正确的行为,但我无法理解为什么会发生(而且我实际上有代码,这不是我所期望的)。

过载分辨率

如果任何候选者是函数模板,则其特化是使用模板参数推导生成的,并且此类特化被视为与非模板函数一样,除非在决胜规则中另有指定。

好的,让我们生成专业化。对于#1来说,这很容易,它就变成了int foo(int& x)。对于 #2,适用特殊扣除规则,因为它是转发参考。i是一个左值,因此T被推导为int&T&&变为int& &&,在引用折叠后变为 just int&,产生结果int foo(int& x)。这与#1 完全相同!

所以我希望看到一个不明确的调用,但这并没有发生。谁能解释一下为什么吗?这里使用什么决定因素来选择最佳可行的功能?

另请参阅Slack 中的相关讨论,其中有一些想法。

c++ templates overloading forwarding-reference

14
推荐指数
1
解决办法
223
查看次数

将相同的值转发给两个或更多函数

使用转发引用时,将相同的值转发给多个函数是不是一个坏主意?考虑以下代码:

template<typename Container>
constexpr auto
front(Container&& c)
-> typename Container::value_type
{ return std::forward<Container>(c).front(); }

template<typename Container>
constexpr auto
back(Container&& c)
-> typename Container::value_type
{ return std::forward<Container>(c).back(); }

template<typename Container>
constexpr auto
get_corner(Container&& c)
{
    return do_something(front(std::forward<Container(c)),
                        back(std::forward<Container>(c));
}
Run Code Online (Sandbox Code Playgroud)

如果Container是左值引用,则该函数可以正常工作.但是,我担心rvalues传递给它的情况,因为一旦移动操作发生,该值将被无效.我的疑问是:在这种情况下,是否有正确的方法来转发容器,而不会丢失价值类别?

c++ c++11 forwarding-reference

12
推荐指数
1
解决办法
1179
查看次数

概念lite如何与通用引用相互作用?

我最近看了一下这个视频,解释了C++中概念精简版的概念,这些概念很可能在今年作为TS出现.现在,我也了解通用引用/转发引用(如描述在这里),并是t &&可以根据上下文两个方面的含义(即,如果类型推演正在执行或没有).这自然会引出概念如何与通用引用相互作用的问题?

为了使它具体化,在下面的例子中我们有

void f(int&& i) {}

int i = 0;
f(i);    // error, looks for f(int&)
f(0);    // fine, calls f(int&&)
Run Code Online (Sandbox Code Playgroud)

template <typename T>
void f(T&& test) {}

int i = 0;
f(i);    // fine, calls f(T&&) with T = int& (int& && = int&)
f(0);    // fine, calls f(T&&) with T = int&& (int&& && = int&&)
Run Code Online (Sandbox Code Playgroud)

但是如果我们使用概念会发生什么?

template <typename T>
    requires Number<T>
void f(T&& test) {}

template <Number T>
void g(T&& test) …
Run Code Online (Sandbox Code Playgroud)

c++ c++-concepts universal-reference forwarding-reference c++17

11
推荐指数
1
解决办法
197
查看次数

返回 auto&amp;&amp; 和 decltype(auto) 有什么区别?

我正在尝试制作模板包装函数,该函数应该转发参数并返回值。我无法决定使用什么auto&&decltype(auto)返回类型更好。我读过 Scott Meyers 的文章,并理解与不剥离 ref_qualifiersdecltype(auto)相比,有必要返回。auto据我了解,同样的论点适用于使用auto&&over auto。现在我有以下问题:

  1. 我对吗,我们返回对象的引用之间decltype(auto)和何时没有区别?auto&&
  2. 如果我们返回对象,会发生什么rvalue,例如:return int{};?返回值会是悬空引用吗?
  3. decltype(auto)和 和有什么区别auto&&?什么更适合作为远期回报类型?

c++ return-type c++14 forwarding-reference decltype-auto

11
推荐指数
1
解决办法
760
查看次数

为什么T const &&不是转发参考?

在模板的上下文中,应用以下"引用折叠"规则:

template <typename T>
void foo(T && t)
{
    //T&  &   -> T&
    //T&  &&  -> T&
    //T&& &   -> T&
    //T&& &&  -> T&&
}
Run Code Online (Sandbox Code Playgroud)

为什么语言禁止使用const限定符的"通用引用" ?

template <typename T>
void foo(T const && t)
Run Code Online (Sandbox Code Playgroud)

如果类型已经解决了参考(4个案例中的3个),那似乎是有意义的.

我确信这个想法与语言的其他一些设计方面不相容,但我看不出全貌.

c++ templates const move-semantics forwarding-reference

10
推荐指数
1
解决办法
241
查看次数

为什么std :: move采用前向引用?

实现std::move基本上如下:

template<typename T>
typename std::remove_reference<T>::type&&
move(T&& t)
{
    return static_cast<typename std::remove_reference<T>::type&&>(t);
}
Run Code Online (Sandbox Code Playgroud)

请注意,参数std::move是通用引用(也称为转发引用,但我们不在此处转发).也就是说,你可以std::move使用左值和左值:

std::string a, b, c;
// ...
foo(std::move(a));       // fine, a is an lvalue
foo(std::move(b + c));   // nonsense, b + c is already an rvalue
Run Code Online (Sandbox Code Playgroud)

但是,由于整个观点std::move都是为了施展到一个rvalue,为什么我们甚至允许std::movervalues呢?如果std::move只接受左值,那会不会更有意义?

template<typename T>
T&&
move(T& t)
{
    return static_cast<T&&>(t);
}
Run Code Online (Sandbox Code Playgroud)

然后,无意义的表达式std::move(b + c)将导致编译时错误.

std::move对于初学者来说,上面的实现也会更容易理解,因为代码完全按照它的样子执行:它需要一个左值并返回一个右值.您不必了解通用引用,引用折叠和元函数.

那么为什么std::move设计同时采用左值和左值?

c++ rvalue move-semantics c++11 forwarding-reference

9
推荐指数
1
解决办法
606
查看次数