标签: perfect-forwarding

C++统一分配运算符移动语义

编辑:解决看到评论 - 不知道如何标记解决与答案.

在c ++ 0x中观看有关完美转发/移动语义的第9频道视频之后,我认为这是编写新分配运算符的好方法.

#include <string>
#include <vector>
#include <iostream>

struct my_type 
{
    my_type(std::string name_)
            :    name(name_)
            {}

    my_type(const my_type&)=default;

    my_type(my_type&& other)
    {
            this->swap(other);
    }

    my_type &operator=(my_type other)
    {
            swap(other);
            return *this;
    }

    void swap(my_type &other)
    {
            name.swap(other.name);
    }

private:
    std::string name;
    void operator=(const my_type&)=delete;  
    void operator=(my_type&&)=delete;
};


int main()
{
    my_type t("hello world");
    my_type t1("foo bar");
    t=t1;
    t=std::move(t1);
}
Run Code Online (Sandbox Code Playgroud)

这应该允许将r值和const分配给它.通过使用适当的构造函数构造一个新对象,然后使用*this交换内容.这对我来说听起来很合理,因为没有数据被复制超过它需要的数量.指针算术很便宜.

但是我的编译器不同意.(g ++ 4.6)我得到了这些错误.

copyconsttest.cpp: In function ‘int main()’:
copyconsttest.cpp:40:4: error: ambiguous overload for ‘operator=’ in ‘t = …
Run Code Online (Sandbox Code Playgroud)

c++ rvo perfect-forwarding c++11

19
推荐指数
1
解决办法
5407
查看次数

为什么一个人永远不会使用auto &&作为局部变量?

虽然T&&与模板一起使用作为转发参考通用引用(如Scott Meyers所称),但我auto&&在代码示例中看到了一些博客.我认为auto自己应该足够了,然而,CbCon 2014中的 Herb Sutter :永远不要auto&&用于局部变量

这是为什么?

看到所有回复,我觉得我应该问对方.尽管有一般编码指南,但是在函数体内使用auto &&以获得代码正确性和可维护性是有任何好的用例.

c++ perfect-forwarding auto c++11 c++14

19
推荐指数
1
解决办法
994
查看次数

为什么必须模仿完美的转发功能?

为什么以下代码有效:

template<typename T1>
void foo(T1 &&arg) { bar(std::forward<T1>(arg)); }

std::string str = "Hello World";
foo(str); // Valid even though str is an lvalue
foo(std::string("Hello World")); // Valid because literal is rvalue
Run Code Online (Sandbox Code Playgroud)

但不是:

void foo(std::string &&arg) { bar(std::forward<std::string>(arg)); }

std::string str = "Hello World";
foo(str); // Invalid, str is not convertible to an rvalue
foo(std::string("Hello World")); // Valid
Run Code Online (Sandbox Code Playgroud)

为什么示例2中的左值不会以与示例1中相同的方式解析?

另外,为什么标准认为需要在std :: forward与简单推导中提供参数类型很重要?无论类型如何,简单地呼唤前方都表现出意图.

如果这不是标准的东西,只是我的编译器,我使用msvc10,这将解释蹩脚的C++ 11支持.

谢谢

编辑1:将文字"Hello World"更改为std :: string("Hello World")以生成rvalue.

c++ perfect-forwarding c++11

18
推荐指数
1
解决办法
3755
查看次数

什么是完美转发设置器的正确`enable_if`约束?

Herb Sutter 回归基础!CppCon 上的现代C++演示要点讨论了传递参数的不同选项,并将其性能与写作/教学的简易性进行了比较."高级"选项(在所有测试的案例中提供最佳性能,但对大多数开发人员来说难以编写)是完美转发,给出了示例(PDF,第28页):

class employee {
    std::string name_;

public:
    template <class String,
              class = std::enable_if_t<!std::is_same<std::decay_t<String>,
                                                     std::string>::value>>
    void set_name(String &&name) noexcept(
      std::is_nothrow_assignable<std::string &, String>::value) {
        name_ = std::forward<String>(name);
    }
};
Run Code Online (Sandbox Code Playgroud)

该示例使用带转发引用的模板函数,模板参数String使用约束enable_if.然而,约束似乎是不正确的:似乎只有在String类型不是a 时才使用此方法std::string,这没有任何意义.这将意味着该std::string成员可以使用设置什么,但一个std::string值.

using namespace std::string_literals;

employee e;
e.set_name("Bob"s); // error
Run Code Online (Sandbox Code Playgroud)

我考虑的一个解释是,有一个简单的拼写错误,而且约束的目的是std::is_same<std::decay_t<String>, std::string>::value代替!std::is_same<std::decay_t<String>, std::string>::value.然而,这意味着setter不能使用,例如,const char *它显然是打算使用这种类型,因为这是在演示文稿中测试的案例之一.

在我看来,正确的约束更像是:

template <class String,
          class = std::enable_if_t<std::is_assignable<decltype((name_)),
                                                      String>::value>>
void set_name(String &&name) …
Run Code Online (Sandbox Code Playgroud)

c++ enable-if perfect-forwarding c++11 forwarding-reference

17
推荐指数
1
解决办法
1247
查看次数

完美转发对象成员

假设我有两个structs:

struct X {};
struct Y { X x; }
Run Code Online (Sandbox Code Playgroud)

我有功能:

void f(X&);
void f(X&&);
Run Code Online (Sandbox Code Playgroud)

我怎样写一个函数g()是需要Y&Y&&只有完美的转发X&X&&f(),分别为:

template <typename T>
void g(T&& t) {
  if (is_lvalue_reference<T>::value) {
    f(t.x);
  } else {
    f(move(t.x));
  }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码说明了我的意图,但随着参数数量的增加,它的可扩展性不高.有没有办法让它完美转发并使其可扩展?

c++ rvalue-reference perfect-forwarding c++11

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

使用std :: forward的构造函数

据我所知,在C++ 11中有效实现构造函数的两种常用方法是使用其中两种

Foo(const Bar& bar) : bar_{bar} {};
Foo(Bar&& bar)      : bar_{std::move(bar)} {};
Run Code Online (Sandbox Code Playgroud)

或者只是一个时尚的

Foo(Bar bar) : bar_{std::move(bar)} {};
Run Code Online (Sandbox Code Playgroud)

使用第一个选项产生最佳性能(例如,在左值的情况下希望是单个副本,在rvalue的情况下希望单个移动),但是对于N个变量需要2个N重载,而第二个选项只需要一个函数通过左值时的额外动作.

在大多数情况下,这不应该产生太大的影响,但肯定两种选择都不是最佳选择.但是,也可以执行以下操作:

template<typename T>
Foo(T&& bar) : bar_{std::forward<T>(bar)} {};
Run Code Online (Sandbox Code Playgroud)

这样做的缺点是允许可能不需要的类型的变量作为bar参数(这是我确信使用模板专门化很容易解决的问题),但无论如何,性能是最佳的,代码随着变量的数量线性增长.

为什么没有人为此目的使用像forward这样的东西?这不是最优化的方式吗?

c++ move-semantics perfect-forwarding c++11

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

完美转发可调用的

我想出了以下代码将R()alike转换为类似void()callable:

#include <utility>

template<class Callable>
auto discardable(Callable&& callable)
{ return [&]() { (void) std::forward<Callable>(callable)(); }; }
//        ^-- is it ok?

int main()
{
    auto f = discardable([n=42]() mutable { return n--; });
    f();
}
Run Code Online (Sandbox Code Playgroud)

我很担心被引用捕获.

  1. 它定义明确吗?
  2. 我保证callable永远不会复制,并且在其生命周期结束后从未使用过吗?

这是标记的C++ 14,但适用于所有以下标准.

c++ lambda perfect-forwarding c++14

16
推荐指数
3
解决办法
1058
查看次数

std :: forward()的右值引用重载的目的是什么?

我正在尝试完美转发,发现 std::forward()需要两个重载:

过载 1:

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

重载nr.2:

template <typename T>
inline T&& forward(typename 
std::remove_reference<T>::type&& t) noexcept
{
    static_assert(!std::is_lvalue_reference<T>::value,
              "Can not forward an rvalue as an lvalue.");
    return static_cast<T&&>(t);
}
Run Code Online (Sandbox Code Playgroud)

现在,完美转发的典型场景是

template <typename T>
void wrapper(T&& e)
{
    wrapped(forward<T>(e));
}
Run Code Online (Sandbox Code Playgroud)

当然,您知道何时wrapper()实例化T取决于传递给它的参数是左值还是右值。如果它是type的左值UT则推导为U&。如果是右值,T则推导为U

无论如何-在-的范围内wrapper()- e是一个左值,因此它始终使用的第一个重载std::forward()

现在我的问题是:

使用(需要)第二重载的有效方案是什么?

c++ perfect-forwarding c++11 c++14 c++17

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

检测(可能是抽象的)基类的受保护构造函数

我正在试验C++ 11的新功能.在我的设置中,我真的很想使用继承构造函数,但遗憾的是没有编译器实现这些.因此,我试图模拟相同的行为.我可以这样写:

template <class T>
class Wrapper : public T {
    public:
    template <typename... As>
    Wrapper(As && ... as) : T { std::forward<As>(as)... } { }
    // ... nice additions to T ...
};
Run Code Online (Sandbox Code Playgroud)

这很有用......大多数时候.有时使用Wrapper类的代码必须使用SFINAE来检测如何Wrapper<T>构造这样的代码.然而,存在以下问题:就重载决策而言,构造函数Wrapper<T>将接受任何参数 - 但是如果不能使用那些构造类型,则编译失败(并且这包括在SFINAE中)T.

我试图使用有条件地启用构造函数模板的不同实例化 enable_if

    template <typename... As, typename std::enable_if<std::is_constructible<T, As && ...>::value, int>::type = 0>
    Wrapper(As && ... as) // ...
Run Code Online (Sandbox Code Playgroud)

哪个工作正常,只要:

  • 适当的构造函数Tpublic
  • T 不是抽象的

我的问题是:如何摆脱上述两个限制?

我试图克服所述第一通过检查(使用SFINAE和sizeof())是否表达new T(std::declval<As &&>()...) …

c++ templates template-meta-programming perfect-forwarding c++11

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

如何在C++ 14中编写通用转发lambda?

如何在C++ 14中编写通用转发lambda?

试试#1

[](auto&& x) { return x; }
Run Code Online (Sandbox Code Playgroud)

在函数体内部,x是一个左值,所以这不起作用.

试试#2

[](auto&& x) { return std::forward<decltype(x)>(x); }
Run Code Online (Sandbox Code Playgroud)

这正确地转发了lambda中的引用,但它总是按值返回(除非编译器省略了副本).

试试#3

[](auto&& x) -> decltype(x) { return std::forward<decltype(x)>(x); }
Run Code Online (Sandbox Code Playgroud)

这将返回与参数相同的类型(可能-> auto&&也会起作用)并且似乎正常工作.

试试#4

[](auto&& x) noexcept -> decltype(x) { return std::forward<decltype(x)>(x); }
Run Code Online (Sandbox Code Playgroud)

添加是否noexcept使这个lambda更适用,因此严格优于#3?

c++ lambda perfect-forwarding c++14

15
推荐指数
2
解决办法
1094
查看次数