Click here to Skip to main content
11,709,536 members (48,227 online)
Click here to Skip to main content

7 reasons C++ devs will love the VS 14 CTP

, 25 Jul 2014 CPOL 22.6K 33
Rate this:
Please Sign up or sign in to vote.
The article goes through sevean language and IDE features in the VS 14 CTP 2 that are specific to C++ development

Introduction

This is by no means a comprehensive list of C++ features added in the VS 14 CTPs, nor does it try to be. It's merely a small selection of C++ language and IDE features that I felt were attractive to a C++ developer from a practical point of view. These are features that I feel developers could start using in their code right away. As for the 7-reasons title, I went for a journalistic title as I couldn't think of a better one.

User-defined literals

User-defined literals is a C++ 11 feature that's been implemented in the VS 14 CTP. Some of the standard headers have already been updated to define user defined literals. Example, <string> has an s-suffix for string literals. So you can do the following now, and both lines of code are identical.

auto s1 = "hello"s;
auto s2 = string("hello");

The definition in <string> (as of the CTP) looks like this:

inline string operator "" s(const char *_Str, size_t _Len)
{ // construct literal from [_Str, _Str + _Len)
  return (string(_Str, _Len));
}

Here's a common example used to demonstrate how you'd use user defined literals in your code. Consider the following Weight class.

struct Weight
{
  WeightUnitType Unit;

  double Value;

  double Lb;

  Weight(WeightUnitType unitType, double value)
  {
    Value = value;
    Unit = unitType;

    if (Unit == WeightUnitType::Lb)
    {
      Lb = value;
    }
    else
    {
      Lb = 2.2 * value;
    }
  }
};

Now here's how you'd define _kg and _lb literal operators for this class.

Weight operator "" _kg(long double value)
{ 
  return (Weight(WeightUnitType::Kg, static_cast<double>(value)));
}

Weight operator "" _lb(long double value)
{
  return (Weight(WeightUnitType::Lb, static_cast<double>(value)));
}

And here's how you'd use them in your code.

auto w1 = 10.0_kg;
auto w2 = 22.0_lb;

cout << (w1.Lb == w2.Lb) << endl; // outputs 1 (true)

Be aware that your literals will need to have a _ as the start of the suffix. Else, you'll just get an error:

literal suffix identifiers that do not start 
with an underscore are reserved

I would assume that <string> does not need an underscore as it's permitted as a special case.

auto return type

Instead of implementing all the C++ 11 features first and then targeting C++ 14, the VC++ team have taken an approach where they will implement both in parallel. This will allow them to implement popular C++ 14 features ahead of less popular C++ 11 features. Either way, at some point, they will have a release which completely supports C++ 11 and C++ 14. One very commonly requested C++ 14 feature is auto/decltype(auto) return types and the CTP supports both. Here's an example, where using it saves some typing and the code looks cleaner.

auto Foo()
{
  map<int, vector<pair<int, string>>> vec;
  return vec;
}

Of course, that is subjective, and some people may feel that the auto is confusing there. It is more useful with templates where the return type would normally need a decltype.

template<class T1, class T2> auto Foo(T1 a, T2 b)
{
  return a + b;
}

You can use it with class methods, and even do forward declarations.

class C
{
public: 
  auto Foo();
};

auto C::Foo()
{
  return 10;
}

Multiple returns are also supported, and that's also for your lambdas.

auto Bar()
{
  C c;
  if (c.Foo() < 10)
  {
    return 3.3;
  }

  return 1.7;
}

Using decltype(auto) gives you even more flexibility. Consider this code.

int F1()
{
  return 5;
}

int  i = 5;
int& F2()
{
  return i;
}

Now if you call these as follows.

auto f1 = F1(); // int - correct
auto f2 = F2(); // int - inaccurate, lost original type
decltype(auto) f3 = F1(); // int - correct
decltype(auto) f4 = F2(); // int& - correct

It's the same with templates, where you can save on a decltype.

struct T
{
  int& Foo(int& i)
  {
    return i;
  }

  double Foo(double& d)
  {
    return d;
  }

  template<class T> decltype(auto) NewWay(T& t)
  {
    return Foo(t);
  }

  template<class T> auto OldWay(T& t) -> decltype(Foo(t))
  {
    return Foo(t);
  }
};

That's a simple example, but library writers would appreciate this as it significantly simplifies their code and makes it way easier to understand when going through someone else's code.

Inheriting constructors

Inheriting constructors is a C++ 11 feature implemented in this CTP. It extends the using declaration to allow a derived class to indicate that it needs to inherit the base class constructors. Here's a basic example.

struct Base
{
  Base(int){}
};

struct Derived : Base
{
  using Base::Base;
};

void Foo()
{
  Derived d1(10); // uses inherited Derived(int)
  Derived d2; // fails to compile, as Base has no default ctor
}

You'll get this error message (as of this CTP).

error C2280: 'Derived::Derived(void)': attempting to
reference a deleted function

Had Base had a default constructor or if the existing int constructor had a default parameter value, it'd have compiled fine.

struct Base
{
  Base(int = 1, int = 2){}
  Base(string){}
};

struct Derived : Base
{
  using Base::Base;
};

void Foo()
{
  Derived d1;
  Derived d2(10);
  Derived d3(10,10);
  string s;
  Derived d4(s);
}

All of those instantiations compile file. You can specify multiple using declarations if you have multiple base classes.

struct Base1
{
  Base1(int){}
};

struct Base2
{
  Base2(int, int){}
};

struct Derived : Base1, Base2
{
  using Base1::Base1;
  using Base2::Base2;
};

void Foo()
{
  Derived d1(1), d2(1, 1);
}

With multiple base classes, you need to make sure there aren't any constructor clashes. Example:

struct Base1
{
  Base1(){}
  Base1(int){}
};

struct Base2
{
  Base2(){}
  Base2(int){}
  Base2(int, int){}
};

struct Derived : Base1, Base2
{
  using Base1::Base1;
  using Base2::Base2;
};

void Foo()
{
  Derived d1(1), d2(1, 1);
}

This won't compile.

error C3882: 'Base2::Base2': constructor has already
been inherited from 'Base1'

The fix is to explicitly declare that constructor in Derived.

struct Derived : Base1, Base2
{
  using Base1::Base1;
  using Base2::Base2;

  Derived(int){}
};

Inheriting constructors work with templates too.

template<class T> struct Derived : T
{
  using T::T;
};

struct Base1
{
  Base1(int){}
};

struct Base2
{
  Base2(int, int){}
};

void Foo()
{
  Derived<Base1> d1(10);
  Derived<Base2> d2(10, 11);
}

This feature will save you from the time and effort required with typing explicit derived constructors by having the compiler generate those for you (making it less error prone as well).

Extended sizeof

C++ 11 proposes a feature to extend sizeof to apply to non-static data members without needing a temporary object. The CTP implements that feature. Consider the following struct.

struct S
{
  int data;
  char data2;
};

Now with Visual Studio 2013, the following code will not compile.

cout << sizeof(S::data) << endl;

You'll get this error message.

Error 1 error C2070: 'unknown': illegal sizeof operand

You'll need to do this instead.

S s;
cout << sizeof(s.data) << endl;
cout << sizeof(s.data2) << endl;

Compare this to the following code supported in the CTP.

cout << sizeof(S::data) << endl;
cout << sizeof(S::data2) << endl;

It's a simple feature but it will help you write cleaner code.

IDE - Create Declaration / Definition

The CTP 2 has a mostly stable implementation of the "Create Declaration / Definition" refactoring tool for your C++ projects. It lets you auto generate the definition or declaration of a member function. Example, if you have a class called Employee, declared in Employee.h and defined in Employee.cpp, you can type in a function declaration into the .h file and have the body auto-generated for you in the cpp file.

Figure 1 : creating a declaration from a definition

You'll get an empty definition.

int Employee::Foo(int x, int y, double d)
{
    return 0;
}

You can do the reverse too. Say you want to add an overload without the double parameter. Just copy paste this definition, remove the double parameter and then use the refactoring option.

Figure 2 : creating a definition from a declaration

That'll generate this for you.

int Foo(int x, int y);

Quite useful. That said, I wish it would do something like this. If I have code as follows.

Employee e;
e.Bar();

If you right click Bar() and choose this refactoring option, you'll get a message that says - "The selected text does not contain any function signatures." Now that would have been handy. C# has had that for at least 2 iterations now.

IDE - Move Definition Location

The CTP adds a refactoring option to move a function definition from header to cpp, or vice-versa. Just right-click on the definition, choose Refactor/Move Definition Location and that's it.

// h file
class Employee
{
public:
  Employee();

  int Foo(int x, int y);
};

// cpp file
Employee::Employee()
{
}

int Employee::Foo(int x, int y)
{
  return 0;
}

Figure 3 : Move definition location between h/cpp files

Now your code looks like this.

class Employee
{
public:
  Employee();

  int Foo(int x, int y)
  {
    return 0;
  }
};

You can do the reverse too. There seems to be a bug in this CTP though - when you move from the h to the cpp, it does not prefix the class-name, so you get this.

int Foo(int x, int y)
{
  return 0;
}

I would assume that this would be fixed in the RTM. Seemingly a minor feature, but it is convenient and once you get used to it, you'll start to miss it when you don't have it (when using an older version or a different IDE).

IDE - Implement Pure Virtuals

This refactoring option implements stub-functions for all pure virtuals in one or all base classes. Here's an example.

class Person
{
public:

  virtual std::string GetName() = 0;
  virtual void SetName(std::string) = 0;
};

class DbEntity
{
public:
  virtual int GetId() = 0;
  virtual void SetId(int) = 0;
};

class Employee : Person, DbEntity
{
public:
  Employee();
};

If you right click on a specific base class, you'll get an option to just implement pure virtuals for that class. If you right click on the derived class name, you'll get the option to implement all pure virtuals for all base types.

Figure 4 : Refactoring tool that implements all pure virtuals

This is what you'll end up with (in the header).

class Employee : Person, DbEntity
{
public:
  Employee();
  // Inherited via Person

  virtual std::string GetName() override;

  virtual void SetName(std::string) override;

  // Inherited via DbEntity

  virtual int GetId() override;

  virtual void SetId(int) override;

};

Corresponding definitions (empty ones) will be generated in the cpp file.

As always, feedback, including critical suggestions, are most welcome. Thank you.

Links

History

  • July 25, 2014 : Link to CTP added
  • July 24, 2014 : First published

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Nish Nishant
United States United States
Nish Nishant is a Software Architect/Consultant based out of Columbus, Ohio. He has over 15 years of software industry experience in various roles including Lead Software Architect, Principal Software Engineer, and Product Manager. Nish is a recipient of the annual Microsoft Visual C++ MVP Award since 2002 (13 consecutive awards as of 2014).

Nish is an industry acknowledged expert in the Microsoft technology stack. He authored
C++/CLI in Action for Manning Publications in 2005, and had previously co-authored
Extending MFC Applications with the .NET Framework for Addison Wesley in 2003. In addition, he has over 140 published technology articles on CodeProject.com and another 250+ blog articles on his
WordPress blog. Nish is vastly experienced in team management, mentoring teams, and directing all stages of software development.

Contact Nish : You can reach Nish on his google email id voidnish.

Website and Blog

You may also be interested in...

Comments and Discussions

 
GeneralMy vote of 5 Pin
Mihai MOGA13-Aug-14 1:39
professionalMihai MOGA13-Aug-14 1:39 
GeneralRe: My vote of 5 Pin
Nish Sivakumar13-Aug-14 3:10
mvpNish Sivakumar13-Aug-14 3:10 
GeneralMy vote of 5 Pin
Agent__0077-Aug-14 18:57
professionalAgent__0077-Aug-14 18:57 
GeneralRe: My vote of 5 Pin
Nish Sivakumar11-Aug-14 5:01
mvpNish Sivakumar11-Aug-14 5:01 
Questionthank you for this nice article. Pin
Vedat Ozan Oner6-Aug-14 4:23
professionalVedat Ozan Oner6-Aug-14 4:23 
AnswerRe: thank you for this nice article. Pin
Nish Sivakumar6-Aug-14 4:25
mvpNish Sivakumar6-Aug-14 4:25 
GeneralMy vote of 5 Pin
Paulo Zemek30-Jul-14 5:58
professionalPaulo Zemek30-Jul-14 5:58 
GeneralRe: My vote of 5 Pin
Nish Sivakumar1-Aug-14 4:08
mvpNish Sivakumar1-Aug-14 4:08 
QuestionExcellent article Pin
Mike Hankey29-Jul-14 8:24
professionalMike Hankey29-Jul-14 8:24 
AnswerRe: Excellent article Pin
Nish Sivakumar29-Jul-14 8:31
mvpNish Sivakumar29-Jul-14 8:31 
Question<string> and no underscore Pin
Bartosz Bielecki27-Jul-14 21:01
memberBartosz Bielecki27-Jul-14 21:01 
AnswerRe: <string> and no underscore Pin
Nish Sivakumar28-Jul-14 3:36
mvpNish Sivakumar28-Jul-14 3:36 
QuestionGreat post Pin
Member 571480927-Jul-14 17:22
memberMember 571480927-Jul-14 17:22 
AnswerRe: Great post Pin
Nish Sivakumar28-Jul-14 3:36
mvpNish Sivakumar28-Jul-14 3:36 
GeneralExcellent article Pin
Manikandan1026-Jul-14 3:16
professionalManikandan1026-Jul-14 3:16 
AnswerRe: Excellent article Pin
Nish Sivakumar28-Jul-14 3:36
mvpNish Sivakumar28-Jul-14 3:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150819.1 | Last Updated 25 Jul 2014
Article Copyright 2014 by Nish Nishant
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid