Initializer with default constructor
struct Foo {
int Bar; string Too;
};
Foo a = { 1234, "Hello" };
// Foo b( 1234, "Hello" ); // compile error
vector c = {
{ 1234, "Hello" },
{ 4321, "World" },
{ 1111, "Good Morning" }
};
When defined a constructor, the default constructor can't be used.
struct Foo {
int Bar; string Too;
Foo(int bar) : Bar(bar) {}
};
// Foo a = { 1234, "Hello" }; // compile error
Foo b{ 1234 };
Foo c(1234);
std::initializer usage
struct Foo {
int sum(const std::initializer_list< int >& list) {
int total = 0;
for (auto& e : list) {
total += e;
}
return total;
}
};
Foo foo;
auto list = { 1, 2, 3 };
assert(foo.sum(list) == 6);
assert(foo.sum({ 1, 2, 3 }) == 6);
assert(foo.sum({}) == 0);
lvalue and rvalue
int a = 42;
int b = 43;
// a and b are both l-values:
a = b; // ok
b = a; // ok
a = a * b; // ok
// a * b is an rvalue:
int c = a * b; // ok, rvalue on right hand side of assignment
// a * b = 42; // error C2106: '=' : left operand must be l-value
Function return is rvalue but can be lvalue if reference returned.
int someValue = { 1212 };
int& foo() { return someValue; }
int foobar() { return someValue; }
// lvalues:
int i = 42;
i = 43; // ok, i is an lvalue
int* p = &i; // ok, i is an lvalue
foo() = 42; // ok, foo() is an lvalue
int* p1 = &foo(); // ok, foo() is an lvalue
// rvalues:
int j = 0;
j = foobar(); // ok, foobar() is an rvalue
// int* p2 = &foobar(); // error C2102: '&' requires l-value
j = 1234; // ok, 42 is an rvalue
Resolving function when argument is reference and universal reference.
struct FooA { int X = 1234; };
FooA RunFooA(const FooA& a) { FooA temp = a; temp.X = 4321; return temp; }
FooA RunFooA(FooA&& a) { a.X = 4321; return a; }
FooA a;
FooA b = RunFooA(a);
FooA c = RunFooA(FooA());
FooA d = RunFooA(std::move(a));
transfer ownership of std::unique_ptr using std::move
std::unique_ptr p1{ new int };
// std::unique_ptr p2 = p1; // error -- cannot copy unique pointers
std::unique_ptr p3 = std::move(p1); // move `p1` into `p2`
// now unsafe to dereference object held by `p1`
auto type resolution
auto a = 3.14; // double
auto b = 1; // int
auto& c = b; // int&
auto d = { 0 }; // std::initializer_list
auto&& e = 1; // int&&
auto&& f = b; // int&
auto g = new auto(123); // int*
delete g;
const auto h = 1; // const int
auto i = 1, j = 2, k = 3; // int, int, int
// auto l = 1, m = true, n = 1.61; // error -- `l` deduced to be int, `m` is bool
// auto o; // error -- `o` requires initializer
no more typing iterator type
std::vector v = { 1, 2, 3, 4 };
std::vector::const_iterator cit1 = v.cbegin();
auto cit2 = v.cbegin();
auto return type using decltype
template
auto AddAnyTwo(X x, Y y) -> decltype(x + y) {
return x + y;
}
assert(AddAnyTwo(1, 2) == 3);
assert(AddAnyTwo(1, 2.0) == 3.0);
assert(AddAnyTwo(1.5, 1.5) == 3.0);
lambda
int LBar = 1;
auto getLBar = [=]{ return LBar; };
assert(getLBar() == 1);
auto addLBar = [=](int y) { return LBar + y; };
assert(addLBar(1) == 2);
auto getLBarRef = [&]() -> int& { return LBar; };
getLBarRef() = 2;
assert(LBar == 2);
lambda capture - reference or not
int x = 1;
auto f1 = [&x] { x = 2; }; // OK: x is a reference and modifies the original
f1();
// auto f2 = [x] { x = 2; }; // ERROR: the lambda can only perform const-operations on the captured value
auto f3 = [x]() mutable { x = 2; }; // OK: the lambda can perform any operations on the captured value
f3();
using as alias
template using Vec = std::vector;
Vec v{}; // std::vector
using String = std::string;
String s{ "foo" };
nullptr
struct Foo
{
void Bar(int) {}
void Bar(char*) {}
};
Foo foo;
foo.Bar(NULL); // should throw error but not with VS2013
foo.Bar(nullptr);
unspecified enum is just a number
enum Week { Monday = 0, Tuesday, Thursday };
enum Month { January = 0, Feburary, };
Month m = January;
if (m == Monday)
{
// danger !!!
m = Feburary;
}
// Specifying underlying type as `unsigned int`
enum class Color : unsigned int { Red = 0xff0000, Green = 0xff00, Blue = 0xff };
// `Red`/`Green` in `Alert` don't conflict with `Color`
enum class Alert : bool { Red = false, Green };
Color redColor = Color::Red;
Alert redAlert = Alert::Red;
// bool isSame = (redColor == redAlert);
// error C2678: binary '==' : no operator found which takes a left-hand operand of type 'CPPTest::testStrongTypedEnum::Color'
// (or there is no acceptable conversion)
delegating constructor
struct Foo {
int foo;
Foo(int foo) : foo(foo) {}
Foo() : Foo(1) {}
};
Foo foo{};
assert( foo.foo == 1 );
be more explicit on function overriding
struct A {
virtual void foo() {}
void bar() {}
};
struct B : A {
void foo() override {}; // correct -- B::foo overrides A::foo
// void bar() override {}; // error C3668 : 'CPPTest::testOverrides::B::bar' : method with override specifier 'override' did not override any base class methods
// void baz() override {}; // error C3668 : 'CPPTest::testOverrides::B::baz' : method with override specifier 'override' did not override any base class methods
};
say final to stop overriding
struct A {
virtual void foo() {}
};
struct B : A {
virtual void foo() final {}
};
struct C : B {
// virtual void foo() {} // error C3248: 'CPPTest::testFinal::B::foo': function declared as 'final' cannot be overridden by 'CPPTest::testFinal::C::foo'
};
say final to stop inheritance
struct A final {};
// error C3246: 'CPPTest::testFinal1::B' : cannot inherit from 'CPPTest::testFinal1::A' as it has been declared as 'final'
// struct B : A {};
delete to stop compiler generating default methods
#pragma warning( push )
#pragma warning( disable : 4822)
class A {
int x;
public:
A(int x) : x(x) {};
A(const A&) = delete;
A& operator=(const A&) = delete;
};
A x{ 123 };
// A y = x; // error C2280: 'CPPTest::testDeletedFunction::A::testDeletedFunction::A(const CPPTest::testDeletedFunction::A &)' : attempting to reference a deleted function
// y = x; // error -- operator= deleted
#pragma warning( pop )
range based iteration
std::vector a{ 1, 2, 3, 4, 5 };
for (int& x : a)
{
x *= 2;
}
// a == { 2, 4, 6, 8, 10 }
for (int x : a)
{
x *= 2;
}
// a == { 2, 4, 6, 8, 10 }
int b[] = { 5, 4, 3, 2, 1 };
for (int& x : b)
{
x *= 3;
}
std::to_string
assertEqual("123", std::to_string(123));
assertEqual("1.200000", std::to_string(1.2));
std::unique_ptr
{
std::unique_ptr p1{ new int };
*p1 = 1234;
assert(*p1 == 1234);
}
{
int *p1 = new int;
*p1 = 1234;
assert(*p1 == 1234);
delete p1;
}
std::unique_ptr and struct
struct Foo { int Bar; string Too; };
std::unique_ptr p1{ new Foo };
p1->Bar = 1234;
p1->Too = "hello";
assert(p1->Bar == 1234);
assert(p1->Too == "hello");
std::make_unique
struct Foo {
Foo(int bar, string too) : Bar(bar), Too(too){}
int Bar; string Too;
};
std::unique_ptr p1;
if (p1 == nullptr)
{
// p1 = new Foo; // compile error
p1 = std::unique_ptr(new Foo(1234, "Hello"));
p1 = std::make_unique(1234, "Hello");
}
unique_ptr to vector
struct Foo {
Foo(int bar, string too) : Bar(bar), Too(too){}
int Bar; string Too;
};
vector< std::unique_ptr > Foos;
Foos.push_back(std::unique_ptr(new Foo(1234, "Hello")));
Foos.push_back(std::make_unique(4321, "World"));
Foos.push_back(std::make_unique(1111, "Good Morning"));
std::shared_ptr
struct Foo { int Bar = 1234; string Too = "Hello"; };
std::shared_ptr p1{ new Foo };
p1->Bar = 4321;
std::shared_ptr p2 = p1;
p2->Too = "World";
assertEqual("World", p1->Too);
auto p3 = make_shared();
assertEqual(1234, p3->Bar);
p1 = p3;
unique_ptr to shared_ptr
struct Foo { int Bar = 1234; string Too = "Hello"; };
std::unique_ptr p1( new Foo );
// std::shared_ptr p2 = p1;
// error C2440 : 'initializing' : cannot convert from 'std::unique_ptr< CPPTest::testSharedPtr1::Foo,std::default_delete <_Ty> >'
// to 'std::shared_ptr'
std::shared_ptr p3 = std::move(p1);
// p1 is dangling now
tuple
// `playerProfile` has type `std::tuple`.
auto playerProfile = std::make_tuple(51, "Frans Nielsen", "NYI");
assertEqual( 51, std::get<0>(playerProfile));
assertEqual( "Frans Nielsen", std::get<1>(playerProfile));
assertEqual( "NYI", std::get<2>(playerProfile));
tie
// With tuples...
std::string playerName;
std::tie(std::ignore, playerName, std::ignore) = std::make_tuple(91, "John Tavares", "NYI");
assertEqual("John Tavares", playerName);
// With pairs...
std::string yes, no;
std::tie(yes, no) = std::make_pair("yes", "no");
assertEqual("yes", yes);
assertEqual("no", no);
No comments:
Post a Comment