Platinum Partner
dotnet,microsoft,c++,visual studio,compiler,.net & windows,win32 & com

Visual C++ Compiler November 2013 CTP

As part of its faster release cadence, Microsoft just released a CTP of the Visual C++ compiler that incorporates more features from the official C++11 standard, the almost-official C++14 standard, and a couple of Microsoft-specific language extensions. It’s available for download here and you can start using it in Visual Studio 2013 by switching the Platform Toolset to CTP_Nov2013. The VC blog covers the basics of what changed. In this post, I would like to illustrate some of these changes with concise examples. This is not an exhaustive list of every added feature; these are just the ones I found most interesting.

C++ property pane - selecting the Platform Toolset

First, a major convenience feature: generic lambdas. This is a C++14 feature that’s already in the November CTP! Essentially, you define a lambda that takes auto parameters and you can use that lambda with any parameter type:

auto la = [](auto x, auto y) { return x + y; };
std::cout << la(5, 5) << std::endl;
std::cout << la(std::string("Hello "), std::string("World")) << std::endl;

// capturing also works!
auto lala = [&la](auto x) { return la(x, x); };
std::cout << lala(10) << std::endl;

The super-major feature in the November CTP is, without doubt, resumable functions and “await” support for PPL tasks. This is obviously inspired by the async/await C# 5.0 keywords, and is designed to make asynchronous methods much easier to consume. Here’s a typical asynchronous API that you might end up consuming in a Win32 application (I’m deliberately not using a C++/CX example of a Windows Store API):

task<HANDLE> open_file_async(wstring, create_file_mode);
task<DWORD> read_file_async(HANDLE, unsigned, char*);

And here’s a typical example of how you’d consume this API with the existing task<T>.then() support to open a file and then read from it:

void read_something_from_file()
{
  const unsigned BUF_SIZE = 256;
  char* buf = new char[BUF_SIZE];

  auto t = create_file_async(L"C:\\temp\\file.txt", create_file_mode::open_existing);
  t.then([](HANDLE fh) {
  auto t2 = read_file_async(fh, BUF_SIZE, buf);
  t2.then([](DWORD read) {
    std::cout << "read " << read << " bytes" << std::endl;
    buf[read - 1] = '';
    std::cout << "text read: " << buf << std::endl;
    CloseHandle(fh);
    delete[] buf;
    });
  });
}

The nested callbacks are getting rather tedious, and if you need a loop to read chunks from the file until some condition is met, you’ll probably need something like a “recursive” lambda invocation to express your intent. The resumable/await language feature, proposed by Microsoft to the C++ standards committee, is much cleaner:

task<void> read_something_from_file() __resumable
{
  const unsigned BUF_SIZE = 256;
  char buf[BUF_SIZE];

  HANDLE fh = __await create_file_async(L"C:\\temp\\file.txt", create_file_mode::open_existing);
  DWORD read = __await read_file_async(fh, BUF_SIZE, buf);
  std::cout << "read " << read << " bytes" << std::endl;
  buf[read - 1] = '';
  std::cout << "text read: " << buf << std::endl;
  CloseHandle(fh);
}

The __resumable keyword indicates that the method is resumable; in other words, it might execute in parts. The __await keyword splits the method into two parts — one that executes synchronously on the calling thread, and one that is executes asynchronously when the task completes. There is lots of machinery involved in making this possible, including fibers and separate stacks of execution, but that’s outside the scope of this language-focused post.

Moving on to smaller features now, the November CTP finally supports a rather obscure C++11 feature, & and && member function qualifiers. As you know, you can overload member functions on constness — you can have two foo() functions, one const and one non-const. The same thing applies to “rvalue-ness” — you can have two foo() functions, one that will be invoked on lvalues and one that will be invoked on rvalues.

This comes in handy when you might optimize for the rvalue case by moving or destroying the current object because you already know that it’s going away. Here’s a contrived example:

class my_string
{
  char* _str;
public:
  my_string(const char* str)
  {
    _str = _strdup(str);
  }
  // Returns a valid allocated string that will not go
  // away when this object is destroyed
  char* str_dangerous() &
  {
    return _strdup(_str);
  }
  // We are garbage anyway, so it's okay to simply return
  // the inner string that the caller is now responsible for
  char* str_dangerous() &&
  {
    auto str = _str;
    _str = nullptr;
    return str;
  }
  ~my_string()
  {
    if (_str != nullptr)
      free(_str);
  }
};

// lvalue my_string, the string is duplicated (2 allocs, 2 frees)
my_string ms("Hello");
char* p = ms.str_dangerous();
free(p);

// rvalue my_string, the string is only alloc'd and free'd once
p = my_string("World").str_dangerous();
std::cout << p << std::endl;
free(p);

Here’s a tiny feature — __func__. This is part of C99 and was incorporated into C++11 as well; it is simply a function-static variable that contains the name of the current function. And in fact, the Microsoft-specific __FUNCSIG__ macro is even more powerful. But still, let’s get it out of our way. The following code:

void func_c99()
{
  std::cout << __func__ << std::endl;
  std::cout << __FUNCSIG__ << std::endl;
}

Produces the following output:

func_c99
void __cdecl func_c99(void)

The next tiny feature is extended sizeof. It used to be the case (before C++11) that the sizeof operator could not be applied to member variables, even if your code is inside the class that contains the member variable. This produced ugliness such as sizeof(((A*)0)->f) to refer to the member variable A::f. This is no longer necessary, and the following code now works:

struct point { int x; int y; };
std::cout << sizeof(point::x) << std::endl;

Next up, type deduction for function return types. This is another C++14 feature! You can now declare a function and say that it returns auto. This was already available for lambda functions, so the parity for standard functions makes perfect sense. For example, the following function is deduced to return an int:

auto f() { return 42; }

Another exotic feature is an extension to the decltype keyword, decltype(auto). There are subtle semantic differences when a type is deduced from auto vs. decltype. For example, consider:

int x = 42;
auto y = x;          // y is int
decltype(x) z = x;   // z is int
decltype((x)) w = x; // w is int&

The obvious corollary is that you should be able to combine the decltype reference semantics with the convenience of the auto keyword. And that’s part of C++14, again implemented in the November CTP for both function return types and local variable declarations:

class not_copyable
{
public:
  not_copyable() = default;
  not_copyable(not_copyable&&) = delete;
  not_copyable(const not_copyable&) = delete;
};
decltype(auto) foo()
{
  static not_copyable x;
  return (x);
}
void bar()
{
  not_copyable x;
  decltype(auto) z = (x);
}

In the preceding example, not_copyable is a non-copyable type, which proves by virtue of not issuing a compilation error that foo returns a not_copyable& and z in bar is a not_copyable& as well.

Well, that’s it for today — a bunch of new language features, some standard and some non-standard, that are part of the November CTP. It’s worth noting that the debugger, IntelliSense, and editor have not been updated with this CTP, so you will see lots of squigglies and IntelliSense errors when using these new features.

I am posting short links and updates on Twitter as well as on this blog. You can follow me: @goldshtn

Published at DZone with permission of {{ articles[0].authors[0].realName }}, DZone MVB. (source)

Opinions expressed by DZone contributors are their own.

{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks
Tweet

{{parent.nComments}}