雁过无痕

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::

1 auto 会自动把 引用 去除掉
 
  int& get();
  auto k = get();     // k的类型是int,而不是int&
 
  Derived object;
  auto&    same_object = (Base&)object;      
  auto  another_object = (Base&)object;  //会重新构造个Base对象  
 
    
2 decltype 有时会自动把 引用 加上

  int x;
  decltype((x)) 和 decltype(*&x) 的类型是int&,而不是int
 
  在宏中使用decltype时,要特别注意别多加了括号。
 
  下面这段代码错在哪里?
    template<typename T, typename R>
    auto min(T t, R r) -> decltype(t < r ? t : r)
    {
      return (t < r ? t : r);
    }
    
  decltype(t < r ? t : r)的类型是T&或R&,而不是所希望的T或R!
 
 
  标准是这样规定的:

The type denoted by decltype(e) is defined as follows:
  — if e is an unparenthesized id-expression or an unparenthesized class member
     access (5.2.5), decltype(e) is the type of the entity named by e. If there
     is no such entity, or if e names a set of overloaded functions, the program
     is ill-formed;
  — otherwise, if e is an xvalue, decltype(e) is T&&, where T is the type of e;
  — otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e;
  — otherwise, decltype(e) is the type of e.
 

3 std::move、std::forward、右值引用
 
  C++11 引入 右值引用,可以做到:函数转发、针对临时对象优化
  move是动词,从字面上理解好像是要移动对象,其实std::move只是简单的将类型转成右值引用而已!!! 可以理解成 cast_to_rvalue_reference 或 treat_as_temporal_object。
 

  void test1(int&&) {}
 
  void test2(int&& value)  //注意:value的类型是int,而不是int&&
  {
     test1(value);    //无法编译通过,因为value的类型是int! 必须转换类型
     test1(static_cast<int&&>(value));      //或者
     test1(std::forward<int>(value));
  }
 
  test2函数中,value的类型是int,而不是int&&。
  这是一个不得已的选择。如果value的类型是int&&的话,就会有副作用:
 
  void increase(int& value) { ++value; }
  void test3(int&& value) { increase(value); }
 
  char ch = 'a';
  test3(ch);  //本意是改变ch值,但实际上ch值不会改变,改变的是临时对像
  通过转发函数test3,increase函数可以修改临时对像,
  这造成程序员犯的错误(如上面的例子),难以在编译时就被找出来。
 
 
  std::forward<T>(value) 等价于 static_cast<T&&>(value),感觉后者更容易理解。
  std::forward 起到的转发作用。如果T类型为 R&、 R&&,经过类型转换后,其类型还是和原来的一样。
  在C++11中
    R&  &   等同于 R&   (在c++03中,R& &这种写法是非法的)
    R&& &   等同于 R&
    R&  &&  等同于 R&
    R&& &&  等同于 R&&
 
posted on 2012-11-22 19:49 flyinghearts 阅读(2855) 评论(4)  编辑 收藏 引用 所属分类: C++

评论

# re: c++11 最反直觉的地方 2012-11-26 15:28 秒大刀
越搞越复杂,反人类  回复  更多评论
  

# re: c++11 最反直觉的地方 2012-12-04 16:19 w
看着就眼花, 还是最简单的最实用, 天天搞些语法糖看着就心烦

  回复  更多评论
  

# re: c++11 最反直觉的地方 2013-05-20 14:56 lili
第一个auto 是很坑。。。  回复  更多评论
  

# re: c++11 最反直觉的地方 2013-08-20 11:00 walfud
我认为楼主看到了现象, 但是没有认真思考为什么会反直觉, 下面给就你的这几个例子, 做一些 "狡辩":

1. auto k = get(); 的例子.
get 返回了一个引用, 但是引用的语义是什么? 就是变量的别名, 因此语义上讲, 返回一个 int & 就是返回一个 int.
至于 auto another_object = (Base &)object; 也是同理, 你对 object 强转为 Base &, 那么就是认为 object 就是一个 Base, 那么 auto 自动构造一个 Base 的新对象也是正确的.
以上两个问题是楼主没有搞清引用的抽象含义, 而过于纠缠代码的实质和语法细节之中.

2. 关于 decltype((x)) 的问题.
暂无.

3. test3(ch) 问题.
首先, 你的程序根本无法编译.
你定义了 void test3(int &&value) {}, 但是, 却这样调用 test3(ch); 变量 ch 是一个具名变量, 怎能和一个右值引用匹配? 所以 test3(ch) 理论上是无法通过编译的.
再说 forward 这个函数, 其实这个函数的唯一目录就是将具名对象变为非具名对象, 因为标准规定, 右值必须是 unname 的, 所以使用 int &&arg 传递参数后, 有了名字, 就需要使用 forward(arg) 去掉名字. 不过完全可以使用 static_cast 代替, 因为做了转换后, 名字就没有了.
最后说引用之间的重叠效果. 这就和带符号的乘法是一样的, & 是负号, && 是正号. 剩下的不用说了吧.  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理