VS2013中的C++11新特性 已翻译 100%

疙瘩 投递于 2013/07/23 10:04 (共 11 段, 翻译完成于 07-26)
阅读 40682
收藏 55
7
加载中

介绍

Visual C++ 2013 Preview 在6月发布了,C++开发者又找到一个编译器可以更好的支持ISO C++ 11 的特性了.本文介绍了这些新的特性并附有代码实例.

你想动手尝试编译文中的这些代码话,需要去下载并安装Visual Studio 2013 Preview (话说:付费吗?),我尚未在其他编译器上测试这些代码,所以我并不知道与Gcc 或Clang的兼容性(可恶的C++).

MtrS
翻译于 2013/07/23 18:35
1

原始字符串字面值

VC++ 2013现在支持原始字符串字面值了。注意:它并不支持统一码字符串字面值。一个原始字符串字面值允许你避免转义那些在HTML,XML和正则表达式里运用得得心应手的特殊字符。下面是一个示例用法:

auto s1 = R"(This is a "raw" string)";
现在,s1是一个指向常量字符串值为“This is a "raw" string”的指针。尽管不支持嵌套双引号,这与C#支持的@string文字是类似的。那么要在一个字符串字面值中嵌入R"(...)"会怎样。这种情况下,你可以使用以下语法:
auto s2 = R"QQ(Example: R"(This is my raw string)")QQ";
现在,s2包含 Example: R"(This is my raw string)"。 在这个例子中,我把QQ作为界定符。这个界定符可以是任何长度不超过16的字符串。原始字符串字面值也可以包含换行:
auto s3 = R"(<tr>
<td>data</td>
</tr>)";
最后,不论他们什么时候添加统一码字符串字面值的支持,你都可以将它们连接起来并构成原始统一码字符串字面值。
jimmyjmh
翻译于 2013/07/24 14:13
1

可变参数模板

可变参数模板是一个允许多个参数的模板。在我看来,这是个提供给库作者而不是给库使用者的特性,所以我也不是很确定它在C++程序员中会有多流行。以下我们用一个非常简单的例子来展示如何在实际开发中使用可变参数模板。

// Variadic template declaration
template<typename... Args> class Test;

// Specialization 1
template<typename T> class Test<T>
{
public:
  T Data;
};

// Specialization 2
template<typename T1, typename T2> class Test<T1, T2>
{
public:
  T1 Left;
  T2 Right;
};

void Foo()
{
  Test<int> data;
  data.Data = 24;

  Test<int, int> twovalues;
  twovalues.Left = 12;
  twovalues.Right = 15;
}

当使用可变参数模板时,智能感应(intellisense)能很好地配合我们的开发。可变参数模板的实现包括一个叫asizeof的函数,这个函数能返回这个模板的参数个数。

template<typename... Args> class Test
{
public:
  size_t GetTCount()
  {
    return sizeof...(Args);
  }
};

// . . .

Test<int> data;
size_t args = data.GetTCount(); //1

Test<int, int, char*> data2;
args = data2.GetTCount(); //3

Test<int, float> data3;
args = data3.GetTCount(); //2

这其实就是一个数个数的例子,但我猜他们之所以使用一个现存的函数名是因为这样子做会让C++程序员们更容易上手。

大志darcy
翻译于 2013/07/23 21:47
1

对于可变参数模板,一个常用的做法就是专攻其中一个参数,然后把其余的参数都变为可选。这个做法可以以递归的形式实现。以下是一个比较傻的例子,但它能让你明白什么时候不应该用可变参数模板,继而更好地了解这个语言特性。

template<typename... Args> class Test;

// Specialization for 0 arguments
template<> class Test<>
{
};

// Specialization for at least 1 argument

template<typename T1, typename... TRest> class Test<T1, TRest...> 
  : public Test<TRest...>
{
public:
  T1 Data;

  // This will return the base type
  Test<TRest...>& Rest() 
  {
    return *this;
  }
};

void Foo()
{
  Test<int> data;
  data.Data = 24;

  Test<int, int> twovalues;
  twovalues.Data = 10;
  // Rest() returns Test<int>
  twovalues.Rest().Data = 11;

  Test<int, int, char*> threevalues;
  threevalues.Data = 1;
  // Rest() returns Test<int, int>
  threevalues.Rest().Data = 2;
  // Rest().Rest() returns Test<char*>
  threevalues.Rest().Rest().Data = "test data";
}

大家请注意了,千万别把代码写成这样。这个例子仅仅是用来教学的,正确的做法我会在下一个章节中告诉大家。

大志darcy
翻译于 2013/07/23 21:59
3

Tuple的实现

我们来看一下std tuple的头文件 (由VC++团队的Stephan T. Lavavej负责维护 - 最初的代码由P.J. Plauger编写),浏览这些代码,让我的大脑几乎要宕掉了。为了更好的理解代码,我将代码进行简化,摘出其中可以访问tuple的值的最少的代码(能够支持读和写)。这有助于理解在设计模板类时,通常可变参数模板是如何通过递归展开来大幅减少代码的行数。

// tuple 
template<class... _Types> class tuple;

// 空tuple
template<> class tuple<> {};

// 递归的tuple定义
template<class _This,
  class... _Rest>
  class tuple<_This, _Rest...>
  : private tuple<_Rest...>
{ 
public:
  _This _Myfirst;
};
zicode
翻译于 2013/07/24 19:18
1
这里的递归特化使用了继承,因此tuple的每个类型成员都确定的时候递归会终止。读取tuple值的时候,tuple_element类起到读取辅助类的作用。
// tuple_element
template<size_t _Index, class _Tuple> struct tuple_element;

// select first element
template<class _This, class... _Rest>
struct tuple_element<0, tuple<_This, _Rest...>>
{
  typedef _This& type;
  typedef tuple<_This, _Rest...> _Ttype;
};

// recursive tuple_element definition
template <size_t _Index, class _This, class... _Rest>
struct tuple_element<_Index, tuple<_This, _Rest...>>
  : public tuple_element<_Index - 1, tuple<_Rest...> >
{ 
};
这里又一次使用了递归继承,同时边界条件也特化了。注意这里的两个typedef,其中一个定义为对应值类型的引用,另一个定义为和tuple_element类型参数相同的tuple类型。因此,给定一个_Index值,在那个递归层次上我们就能得到对应tuple的类型和tuple值的类型。下面的get方法就使用了这个特性。
// get reference to _Index element of tuple
template<size_t _Index, class... _Types> inline
  typename tuple_element<_Index, tuple<_Types...>>::type
  get(tuple<_Types...>& _Tuple)
{
  typedef typename tuple_element<_Index, tuple<_Types...>>::_Ttype _Ttype;
  return (((_Ttype&) _Tuple)._Myfirst);
}
osc_877575
翻译于 2013/07/26 12:28
2
注意返回类型,它使用上面定义的类型 typedef。同样,元组(tupleis)转换为上述定义过的类型 _TType ,然后我们访问 _Myfirst 成员 (它表示的值)。现在你可以如下所示,编写代码,
tuple<int, char> t1;
get<0>(t1) = 959;
get<1>(t1) = 'A';

auto v1 = get<0>(t1);
auto v2 = get<1>(t1);
现在 不用 我会 只是 可以 肯定 的是 ------ 里只 为了 演示 要在 实际 代码 使用 这些 方法, 而是调用 std::tuple, 它可以完成比 一切多的功能 这就是为什么他有800行长).
MtrS
翻译于 2013/07/26 09:11
1

代理构造函数

代理构造函数已经在C#中用了好长时间,所以将其引入到C++中也很不错。编译器允许一个类型的构造函数(代理构造函数)在其初始化列表中包含另一个构造函数。以前编写代码形式如下:

class Error
{
public:
  Error()
  {
    Init(0, "Success");
  }

  Error(const char* message)
  {
    Init(-1, message);
  }

  Error(int errorCode, const char* message)
  {
    Init(errorCode, message);
  }

private:
  void Init(int errorCode, const char* message)
  {
    //...
  }
};
采用代理构造函数是,可以写成如下形式:
class Error
{
public:
  Error() : Error(0, "Success")
  {
  }

  Error(const char* message) : Error(-1, message)
  {
  }

  Error(int errorCode, const char* message)
  {
    // ...
  }
};
相关阅读Herb Sutter和Jim Hyslop在十年前(2003年5月)写的一篇有趣的关于代理构造函数的文章。
soaring
翻译于 2013/07/25 11:18
1

函数模板中的默认模板参数

这是VC++ 2013现在支持的另一项C++ 11特性。目前为止,下面的代码仍然无法通过VC++编译。

template <typename T = int> void Foo(T t = 0) { }

// error C4519: default template arguments are only 
// allowed on a class template
Visual C++ 2013 能够顺利编译这些代码,模板参数推断也能正确进行。
Foo(12L); // Foo<long>
Foo(12.1); // Foo<double>
Foo('A'); // Foo<char>
Foo(); // Foo<int>
这项特性的实用性在下面的例子里尤为明显。
template <typename T> class Manager 
{
public:
  void Process(T t) { }
};

template <typename T> class AltManager
{
public:
  void Process(T t) { }
};

template <typename T, typename M = Manager<T>> void Manage(T t)
{
  M m;
  m.Process(t);
}

Manage(25); // Manage<int, Manager<int>>
Manage<int, AltManager<int>>(25); // Manage<int, AltManager<int>>
并不是所有的参数都需要默认参数。
template <typename B, typename T = int> void Bar(B b = 0, T t = 0) { }

Bar(10); // Bar<int, int>
Bar(10L); // Bar<long, int>
Bar(10L, 20L); // Bar<long, long>
Bar(); // will not compile
如果带默认参数的函数模板有重载的话,类型无法推断的时候编译器将会给出错误。
template <typename T = int> void Foo(T t = 0) { }
template <typename B, typename T = int> void Foo(B b = 0, T t = 0) { }

Foo(12L); // will not compile
Foo(12.1); // will not compile
Foo('A'); // will not compile
Foo(); // Foo<int>

使用函数模板的默认模板参数时应当在这里注意。

osc_877575
翻译于 2013/07/25 20:05
1

显式转换运算符

我仍然记得2004年八月的一天,那个时候我意识到尽管我是一个还不错的C++程序员,我对explicit关键字一无所知,这令我十分局促不安。那之后我写了一篇博客文章

简单说明一下explicit的使用。考虑一下下面的例子。

class Test1
{
public:
  explicit Test1(int) { }
};

void Foo()
{
  Test1 t1(20);
  Test1 t2 = 20; // will not compile
}
尽管转换构造函数可以达到这一目的,转换运算符因为缺乏标准支持而无法完成类似的任务。坏消息是你无法确保转换构造函数和转换运算符的行为是一致的。考虑一下下面的例子。
class Test1
{
public:
  explicit Test1(int) { }
};

class Test2
{
  int x;
public:
  Test2(int i) : x(i) { }
  operator Test1() { return Test1(x); }
};

void Foo()
{
  Test2 t1 = 20;
  Test1 t2 = t1; // will compile
}
上面的代码能通过编译。现在有了C++ 11的新特性,explicit也可以用在转换运算符上了。
class Test2
{
  int x;
public:
  Test2(int i) : x(i) { }
  explicit operator Test1() { return Test1(x); }
};

void Foo()
{
  Test2 t1 = 20;
  Test1 t2 = (Test1)t1; // this compiles
  Test1 t3 = t1; // will not compile
}
下面的这个例子里隐式应用了bool类型的转换运算符。
class Test3
{
public:
  operator bool() { return true; }
};

void Foo()
{
  Test3 t3;
  if (t3)
  {
  }

  bool b = t3;
}
这段代码能通过编译。现在试一下在运算符上加上explicit关键字
class Test3
{
public:
  explicit operator bool() { return true; }
};

void Foo()
{
  Test3 t3;
  if (t3) // this compiles!
  {
  }

  bool b = t3; // will not compile
}

正如预期,第二个转换无法通过编译,但是第一个通过了。这是因为if里的bool转换被视为显式转换。因此在这里你要小心谨慎,仅仅添加explicit关键字无法防止意外情况下的类型转换,类型可能仍然是不安全的。

osc_877575
翻译于 2013/07/25 20:23
1
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(42)

wliuxingxiangyu
wliuxingxiangyu
mark
USIDCBBS
USIDCBBS
2013看上去不错,准备买个256G SSD,重装系统再升级
wcrack
wcrack

不要社么说,microsoft在大中国的ZF采购中绝对占比到80%以上,采购了windows平台,vs就是大行其道的理由,所以以后中国的在vs开发者不会减少,虽然这里是开源社区。大家都看不起ms

楚山
visual studio的支持C++11 没有g++做得好啊,见链接:
http://cpprocks.com/c11-compiler-support-shootout-visual-studio-gcc-clang-intel/
看来得换个环境了
x
xermao

引用来自“int03h”的评论

引用来自“有人知是燕归来”的评论

引用来自“int03h”的评论

引用来自“有人知是燕归来”的评论

引用来自“int03h”的评论

引用来自“有人知是燕归来”的评论

引用来自“int03h”的评论

引用来自“有人知是燕归来”的评论

这些东西一年前的时候gcc和clang都做好了,现在发这个有毛用?今年3月份gcc已完全支持c++11的所有特性,clang已经在计划支持c++14了。完全过时的东西就不要再发了

实际开发中有多少用到C++11的

我的意思是,一年之前这一类的文章已经一大堆了,再发就没有什么意思了。自己非要死守着vs,等到人家都用了好久自己才像发现新大陆一样,不觉得可悲吗

不是每个人都只用Linux,不是每个人都只开发Linux应用。这文章也许对在Linux平台工作的人来说,没意义,但是,对用C++开发windows应用的人来说,这文章就有意义了。这个世界不是你一个人的世界,你只用linux不代表别人也只用Linux。也许是我见识少,至今我没见过Windows平台上比VS还好的集成开发环境。

我觉得讨论的重心是语言,而不是工具和平台的差异。既然是标准,那么所有的平台和工具实现出来的效果都应该是一样的。你上面那些代码和文字,在每一个平台上都是一样的。我说的无意义就是指这些,因为之前有无数的同样的内容已经出现了。如果你想提供给别人一些由价值的信息,应该去做的是发掘那些vs所提供的独特的地方或者在其具体的标准实现上有什么可圈可点的地方。这篇文章对于用C++开发windows的人来说,其实有用的就一句话:"VS已经支持C++新标准了"或者详细一点,一个列表,列出支持了哪些特性就行了,当然,我指的不是那种眼里只有一种工具的人。

你是牛人,这文章分明是主要讲VS实现的新特性,你给我扯到重心是语言。你仔细看看标题是什么。这文章是给用VS的人看的,不是给你们这些纯用语言不用工具的人看的。对你来说没意义,但这文章对用VS的人来说是有意义的。你非要说列出支持哪些特性,难道这不是列出?难道是一句话列出,再让我们去一项项查?

即使只用vS的人也不是非要等到Vs支持新特性了才去关注那些新特性。我的话是对那些关注C++发展的人说的,不是眼里只有VS的人说的。

你看文章面向的是谁,你再说这文章有没有用。凡是不考虑背景说话的都是在耍流氓。

我就是只用VS开发的程序员,对linux一点兴趣都没,所以我觉得这篇文章很有用。有人知是燕归来这货就是想来秀高端,生怕别人不知道他有多牛逼。我一般只有VS更新后才去关注支持什么新特性了,平时一般都不关注C++的新特性的。
h
hanf
微软这神马速度
chai2010
chai2010
刚从VC2010升级到VC2012, 顶一个!
int03h
int03h

引用来自“有人知是燕归来”的评论

引用来自“int03h”的评论

引用来自“有人知是燕归来”的评论

引用来自“int03h”的评论

引用来自“有人知是燕归来”的评论

引用来自“int03h”的评论

引用来自“有人知是燕归来”的评论

这些东西一年前的时候gcc和clang都做好了,现在发这个有毛用?今年3月份gcc已完全支持c++11的所有特性,clang已经在计划支持c++14了。完全过时的东西就不要再发了

实际开发中有多少用到C++11的

我的意思是,一年之前这一类的文章已经一大堆了,再发就没有什么意思了。自己非要死守着vs,等到人家都用了好久自己才像发现新大陆一样,不觉得可悲吗

不是每个人都只用Linux,不是每个人都只开发Linux应用。这文章也许对在Linux平台工作的人来说,没意义,但是,对用C++开发windows应用的人来说,这文章就有意义了。这个世界不是你一个人的世界,你只用linux不代表别人也只用Linux。也许是我见识少,至今我没见过Windows平台上比VS还好的集成开发环境。

我觉得讨论的重心是语言,而不是工具和平台的差异。既然是标准,那么所有的平台和工具实现出来的效果都应该是一样的。你上面那些代码和文字,在每一个平台上都是一样的。我说的无意义就是指这些,因为之前有无数的同样的内容已经出现了。如果你想提供给别人一些由价值的信息,应该去做的是发掘那些vs所提供的独特的地方或者在其具体的标准实现上有什么可圈可点的地方。这篇文章对于用C++开发windows的人来说,其实有用的就一句话:"VS已经支持C++新标准了"或者详细一点,一个列表,列出支持了哪些特性就行了,当然,我指的不是那种眼里只有一种工具的人。

你是牛人,这文章分明是主要讲VS实现的新特性,你给我扯到重心是语言。你仔细看看标题是什么。这文章是给用VS的人看的,不是给你们这些纯用语言不用工具的人看的。对你来说没意义,但这文章对用VS的人来说是有意义的。你非要说列出支持哪些特性,难道这不是列出?难道是一句话列出,再让我们去一项项查?

即使只用vS的人也不是非要等到Vs支持新特性了才去关注那些新特性。我的话是对那些关注C++发展的人说的,不是眼里只有VS的人说的。

你看文章面向的是谁,你再说这文章有没有用。凡是不考虑背景说话的都是在耍流氓。
有人知是燕归来
有人知是燕归来

引用来自“int03h”的评论

引用来自“有人知是燕归来”的评论

引用来自“int03h”的评论

引用来自“有人知是燕归来”的评论

引用来自“int03h”的评论

引用来自“有人知是燕归来”的评论

这些东西一年前的时候gcc和clang都做好了,现在发这个有毛用?今年3月份gcc已完全支持c++11的所有特性,clang已经在计划支持c++14了。完全过时的东西就不要再发了

实际开发中有多少用到C++11的

我的意思是,一年之前这一类的文章已经一大堆了,再发就没有什么意思了。自己非要死守着vs,等到人家都用了好久自己才像发现新大陆一样,不觉得可悲吗

不是每个人都只用Linux,不是每个人都只开发Linux应用。这文章也许对在Linux平台工作的人来说,没意义,但是,对用C++开发windows应用的人来说,这文章就有意义了。这个世界不是你一个人的世界,你只用linux不代表别人也只用Linux。也许是我见识少,至今我没见过Windows平台上比VS还好的集成开发环境。

我觉得讨论的重心是语言,而不是工具和平台的差异。既然是标准,那么所有的平台和工具实现出来的效果都应该是一样的。你上面那些代码和文字,在每一个平台上都是一样的。我说的无意义就是指这些,因为之前有无数的同样的内容已经出现了。如果你想提供给别人一些由价值的信息,应该去做的是发掘那些vs所提供的独特的地方或者在其具体的标准实现上有什么可圈可点的地方。这篇文章对于用C++开发windows的人来说,其实有用的就一句话:"VS已经支持C++新标准了"或者详细一点,一个列表,列出支持了哪些特性就行了,当然,我指的不是那种眼里只有一种工具的人。

你是牛人,这文章分明是主要讲VS实现的新特性,你给我扯到重心是语言。你仔细看看标题是什么。这文章是给用VS的人看的,不是给你们这些纯用语言不用工具的人看的。对你来说没意义,但这文章对用VS的人来说是有意义的。你非要说列出支持哪些特性,难道这不是列出?难道是一句话列出,再让我们去一项项查?

即使只用vS的人也不是非要等到Vs支持新特性了才去关注那些新特性。我的话是对那些关注C++发展的人说的,不是眼里只有VS的人说的。
int03h
int03h

引用来自“有人知是燕归来”的评论

引用来自“int03h”的评论

引用来自“有人知是燕归来”的评论

引用来自“int03h”的评论

引用来自“有人知是燕归来”的评论

这些东西一年前的时候gcc和clang都做好了,现在发这个有毛用?今年3月份gcc已完全支持c++11的所有特性,clang已经在计划支持c++14了。完全过时的东西就不要再发了

实际开发中有多少用到C++11的

我的意思是,一年之前这一类的文章已经一大堆了,再发就没有什么意思了。自己非要死守着vs,等到人家都用了好久自己才像发现新大陆一样,不觉得可悲吗

不是每个人都只用Linux,不是每个人都只开发Linux应用。这文章也许对在Linux平台工作的人来说,没意义,但是,对用C++开发windows应用的人来说,这文章就有意义了。这个世界不是你一个人的世界,你只用linux不代表别人也只用Linux。也许是我见识少,至今我没见过Windows平台上比VS还好的集成开发环境。

我觉得讨论的重心是语言,而不是工具和平台的差异。既然是标准,那么所有的平台和工具实现出来的效果都应该是一样的。你上面那些代码和文字,在每一个平台上都是一样的。我说的无意义就是指这些,因为之前有无数的同样的内容已经出现了。如果你想提供给别人一些由价值的信息,应该去做的是发掘那些vs所提供的独特的地方或者在其具体的标准实现上有什么可圈可点的地方。这篇文章对于用C++开发windows的人来说,其实有用的就一句话:"VS已经支持C++新标准了"或者详细一点,一个列表,列出支持了哪些特性就行了,当然,我指的不是那种眼里只有一种工具的人。

你是牛人,这文章分明是主要讲VS实现的新特性,你给我扯到重心是语言。你仔细看看标题是什么。这文章是给用VS的人看的,不是给你们这些纯用语言不用工具的人看的。对你来说没意义,但这文章对用VS的人来说是有意义的。你非要说列出支持哪些特性,难道这不是列出?难道是一句话列出,再让我们去一项项查?
返回顶部
顶部