c++11 idioms @ silicon valley code camp 2012
DESCRIPTION
C++11 feels like a new language. Compared to its previous standards, C++11 packs more language features and libraries designed to make C++ programs easier to understand and faster. As the community is building up experience with the new features, new stylistic ways of using them are emerging. These styles (a.k.a. idioms) give the new language its unique flavor. This talk will present emerging idioms of using rvalue references -- a marquee feature of C++11 as many renowned experts call it. You will see how C++11 opens new possibilities to design class interfaces. Finally, you will learn some advanced use-cases of rvalue references which will likely make you feel something amiss in this flagship feature of C++11.TRANSCRIPT
![Page 1: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/1.jpg)
Sumant Tambe, Ph.D. Senior Software Research Engineer Real-Time Innovations, Inc.
http://cpptruths.blogspot.com
![Page 2: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/2.jpg)
Author
Blogger
Library Developer
![Page 3: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/3.jpg)
Definitions taken from Answers.com and Google.com
This talk is about programming language idioms
![Page 4: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/4.jpg)
» Idioms ˃ Specific grammatical, syntactic, structural
expressions in a given programming language to solve an implementation problem
˃ Often have names—create vocabulary like patterns
˃ Repeat themselves
˃ Often cannot be modularized as libraries
˃ May get promoted as first-class features as a language evolves
» Idioms vs. Patterns ˃ Idioms are patterns specific to a language
˃ Patterns are language independent
![Page 5: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/5.jpg)
» Idioms of Using C++11 Rvalue References
» C++ Truths ˃ Rvalue References In Constructor: When Less Is More
˃ Perfect Forwarding of Parameter Groups in C++11
» A Sense of Design – Boris Kolpackov ˃ Efficient Argument Passing in C++11 (Parts 1, 2, and 3) (with permission)
![Page 6: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/6.jpg)
![Page 7: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/7.jpg)
class Book { // .... private: std::string _title; std::vector<std::string> _authors; std::string _publisher; size_t _pub_year; };
![Page 8: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/8.jpg)
class Book { public: Book(const std::string & title, const std::vector<std::string> & authors, const std::string & pub, const size_t & pub_year); // .... private: std::string _title; std::vector<std::string> _authors; std::string _publisher; size_t _pub_year; };
Good old C++03 constructor
» Other alternatives ˃ An iterator-pair instead of const std::vector<std::string>&
˃ but lets keep it simple
![Page 9: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/9.jpg)
class Book { public: Book(const std::string & title, const std::vector<std::string> & authors, const std::string & pub, const size_t & pub_year) : _title(title), _authors(authors), _publisher(pub), _pub_year(pub_year) {} private: std::string _title; std::vector<std::string> _authors; std::string _publisher; size_t _pub_year; };
Constructor parameters
make copies in *this
Is this class move enabled?
![Page 10: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/10.jpg)
class Book { public: Book(const std::string & title, const std::vector<std::string> & authors, const std::string & pub, const size_t & pub_year); Book (const Book &) = default; // Copy Constructor Book & operator = (const Book &) = default; // Copy Assign Book (Book &&) = default; // Move Constructor Book & operator = (Book &&) = default; // Move Assign ~Book() = default; // Destructor private: std::string _title; std::vector<std::string> _authors; std::string _publisher; size_t _pub_year; };
No need to write these declarations
Compiler will provide them
where appropriate
![Page 11: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/11.jpg)
But, I Just READ About Rvalue References!
![Page 12: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/12.jpg)
class Book { public: Book(const std::string & title, const std::vector<std::string> & authors, const std::string & pub, const size_t & pub_year); // Old c-tor Book(std::string && title, std::vector<std::string> && authors, std::string && pub, size_t && pub_year) : _title(std::move(title)), _authors(std::move(authors)), _publisher(std::move(publisher), _pub_year(std::move(pub_year)) {} // ... Members not shown };
Constructor with C++11 rvalue references
Is it now optimally move enabled?
![Page 13: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/13.jpg)
class Book { public: Book(const std::string & title, const std::vector<std::string> & authors, const std::string & pub, const size_t & pub_year); // Old constructor Book(std::string && title, std::vector<std::string> && authors, std::string && pub, size_t && pub_year) // New constructor : _title(std::move(title)), _authors(std::move(authors)), _publisher(std::move(publisher), _pub_year(std::move(pub_year)) {} }; int main(void) { std::vector<std::string> authors { "A", "B", "C" }; Book b1("Book1", authors, "O’Reilly", 2012); const size_t year = 2012; Book b2("Book1", { "Author" }, "O’Reilly", year); Book b3("Book", { "Author" }, "O’Reilly", 2012); // Calls New Ctor }
Calls old constructor!
Calls old constructor!
![Page 14: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/14.jpg)
Book::Book(std::string && title, std::vector<std::string> && authors, std::string && pub, size_t && pub_year); // New constructor int main(void) { std::vector<std::string> authors { "A", "B", "C" }; Book b1("Book1", authors, "O’Reilly", 2012); const size_t year = 2012; Book b2("Book1", { "Author" }, "O’Reilly", year); Book b3("Book", { "Author" }, "O’Reilly", 2012); }
lvalue
lvalue
No lvalue
» Even one incompatible parameter (lvalue) will cause the compiler to reject the new rvalue-only constructor
![Page 15: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/15.jpg)
title authors pub year
string && vector<string> && string && size_t
string && vector<string> && const string & size_t
string && const vector<string> & string && size_t
string && const vector<string> & const string & size_t
const string & vector<string> && string && size_t
const string & vector<string> && const string & size_t
const string & const vector<string> & string && size_t
const string & const vector<string> & const string & size_t
» Fortunately an optimal solution exists!
» But has a small problem 8 constructors!
˃ Implementations of all the constructors are different!
˃ Each Rvalue reference object must be std::moved
˃ In general exponential number of constructors
![Page 16: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/16.jpg)
class Book { public: Book(std::string title, std::vector<std::string> authors, std::string pub, size_t pub_year) : _title (std::move(title)), _authors (std::move(authors)), _publisher(std::move(pub)), _pub_year (std::move(pub_year)) {} };
» Help the compiler take the best decision ˃ Pass-by-value!
˃ std::move each parameter
˃ Compiler makes no more copies than absolutely necessary
˃ Copy-elision may avoid moves too!
Only one constructor
![Page 17: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/17.jpg)
class Book { public: Book(std::string title, std::vector<std::string> authors, std::string publisher, size_t pub_year) : _title (std::move(title)), _authors (std::move(authors)), _publisher(std::move(publisher)), _pub_year (pub_year) {} }; std::string publisher() { // ... } int main(void) { std::vector<std::string> authors { "A", "B", "C" }; Book b1("Book1", authors, publisher(), 2012); }
ctor + 1 move
Copy-ctor + 1 move
2 moves 2 copies
lvalue
![Page 18: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/18.jpg)
» Move is not free!
˃ Potentially 5 to 15 % performance degradation
˃ Benchmark!
» Many types don’t have efficient move operations
˃ std::array, std::complex, etc.
˃ Many C++03 libraries have not caught up with C++11
+ Compiler will not provide implicit move operations (in most cases)
» Move may be same as copy!
˃ Move construction Use move-ctor if available, otherwise use copy-ctor!!
˃ Move==Copy when strings are small (small string optimization)
» Works best only when you know you are going to make a copy
![Page 19: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/19.jpg)
A sense of design
![Page 20: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/20.jpg)
» matrix is movable (efficiently)
» matrix is copyable too
» operator + makes a copy
˃ Lets try to save it if we can!
matrix operator+ (const matrix& x, const matrix& y) { matrix r (x); r += y; return r; }
![Page 21: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/21.jpg)
matrix operator+ (matrix&& x, const matrix& y) { matrix r (std::move(x)); r += y; return r; } matrix a, b; matrix c = a * 2 + b; matrix d = a + b * 2;
Look ma! No Copy!
Works great!
Oops!
![Page 22: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/22.jpg)
matrix operator+ (const matrix& x, const matrix& y) { matrix r (x); r += y; return r; } matrix operator+ (const matrix& x, matrix&& y) { matrix r (std::move(y)); r += x; return r; } matrix operator+ (matrix&& x, const matrix& y) { matrix r (std::move(x)); r += y; return r; } matrix operator+ (matrix&& x, matrix&& y) { matrix r (std::move(x)); r += y; return r; }
ARE YOU KIDDING
ME?
In general, exponential number of implementations
![Page 23: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/23.jpg)
» Pass-by-value!
matrix operator+ (matrix x, matrix y) { matrix r (std::move(x)); r += y; return r; } matrix a, b; matrix c = a*2 + b*4; matrix d = a + b*4; matrix e = a*2 + b; matrix f = a + b;
Works great!
Two Unnecessary Moves
One Unnecessary Copy and Move
We need a way to detect lvalue/rvalue at runtime
![Page 24: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/24.jpg)
![Page 25: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/25.jpg)
» Pass original type to a forwarded function ˃ Forward lvalues as lvalues
˃ Forward const lvalues as const lvalues
˃ Forward rvalues as rvalues
» Works very well with factory functions
struct X { ... }; void g(X&& t); // A void g(X& t); // B template<typename T> void f(T&& t) { g(std::forward<T>(t)); } int main() { X x; f(x); // Calls B f(X()); // Calls A }
template <class Arg> Blob * createBlob(Arg&& arg) { return new Blob(std::forward<Arg>(arg)); }
![Page 26: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/26.jpg)
» Perfect forwarding can be made to work … But
» First, you must use a template
» Second, you need two template parameters (T and U)
» Then you must restrict them to the specific type you are interested in (i.e., matrix)
˃ Most likely using enable_if
» Finally, you need to ask the right question
˃ IS_RVALUE(T, x)? #define IS_RVALUE(TYPE, VAR) \ (std::is_rvalue_reference<decltype(std::forward<TYPE>((VAR)))>::value) (!std::is_reference<TYPE>::value)
In short, It is too much noise!
![Page 27: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/27.jpg)
Parameter Example Best Case Sub-optimal Case
Const Reference
f(const matix &); Function makes no copy and pass lvalue
Function makes a copy and pass rvalue (missed optimization)
Pass-by-value f(matrix); Function makes a copy and pass rvalue
Function makes no copy and pass lvalue (unnecessary copy)
Const Reference AND Rvalue Reference
f(const matrix &); AND f(matrix &&);
All cases For N parameters, 2N implementations
Perfect Forwarding (T &&)
template <class T> f(T&&);
When you need a template
When you don’t want a template (complex use of enable_if)
Can we do better?
![Page 28: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/28.jpg)
» A type that 1. Binds to lvalues as const reference
2. Binds to rvalues as rvalue reference
3. Determines lvalue/rvalue at run-time
4. Does not force the use of templates
5. Causes no code bloat
6. Is built-in
» Const reference does not satisfy #3
» Perfect forwarding does not satisfy #4
» std::reference_wrapper does not satisfy #2 and #3
![Page 29: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/29.jpg)
template <typename T> struct in { in (const T& l): v_ (l), rv_ (false) {} in (T&& r) : v_ (r), rv_ (true) {} bool lvalue () const { return !rv_; } bool rvalue () const { return rv_; } operator const T& () const { return v_; } const T& get () const { return v_; } T&& rget () const { return std::move (const_cast<T&> (v_)); } T move () const { if (rv_) return rget (); else return v_; } private: const T& v_; bool rv_; };
![Page 30: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/30.jpg)
» No template!
» Simple, self-explanatory
» Can be even shorter!
matrix operator + (in<matrix> m1, in<matrix> m2) { if(m1.rvalue()) { matrix r(m1.rget()); r += m2.get(); return r; } else if(m2.rvalue()) { matrix r(m2.rget()); r += m1.get(); return r; } else { matrix r(m1.get()); r += m2.get(); return r; } }
![Page 31: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/31.jpg)
» Idiom useful only when copies of parameters are made conditionally ˃ See authors blog for more details
» Not clean when ambiguous implicit conversions are involved ˃ See authors blog for more details
» Not well-known yet ˃ May be surprising to some
» More critical eyes needed ˃ Propose in Boost?
» Should be built-in, ideally ˃ Propose a language extension for C++1y?
![Page 32: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/32.jpg)
![Page 33: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/33.jpg)
class Blob { private: std::vector<std::string> _v; };
» Initialize Blob Initializing Blob::_v
» C++11 std::vector has 9 constructors!
» Question: How to write Blob’s constructor(s) so that all the vector’s constructors could be used?
int main(void) { const char * shapes[3] = { "Circle", "Triangle", "Square" }; Blob b1(5, "C++ Truths"); // Initialize Blob::_v with 5 strings Blob b2(shapes, shapes+3); // Initialize Blob::_v with 3 shapes }
![Page 34: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/34.jpg)
class Blob { std::vector<std::string> _v; public: template<class Arg1, class Arg2> Blob(Arg1&& arg1, Arg2&& arg2) : _v(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2)) { } }; int main(void) { const char * shapes[3] = { "Circle", "Triangle", "Square" }; Blob b1(5, "C++ Truths"); // OK Blob b2(shapes, shapes+3); // OK }
Perfect forward two parameters
![Page 35: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/35.jpg)
class Blob { std::vector<std::string> _v; public: template<class Arg1, class Arg2> Blob(Arg1&& arg1, Arg2&& arg2) : _v(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2)) { } }; int main(void) { Blob b3; // Default constructor. Does not compile! Blob b4(256); // 256 empty strings. Does not compile! }
Perfect forward two parameters
![Page 36: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/36.jpg)
class Blob { std::vector<std::string> _v; public: template<class... Args> Blob(Args&&... args) : _v(std::forward<Args>(args)...) { } }; int main(void) { const char * shapes[3] = { "Circle", "Triangle", "Square" }; Blob b1(5, "C++ Truths"); // OK Blob b2(shapes, shapes+3); // OK Blob b3; // OK Blob b4(256); // OK }
![Page 37: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/37.jpg)
class Blob { std::vector<std::string> _v; std::list<double> _l public: template<class... Args> Blob(Args&&... args) : _v(???), _l(???) { } }; int main(void) { // Initialize Blob::_v with 5 strings and // Blob::_l with { 99.99, 99.99, 99.99 } Blob b1(5, "C++ Truths", 3, 99.99); // Does not compile! }
What parameters are for _v and
what are for _l?
![Page 38: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/38.jpg)
» But std::vector and std::list don’t accept std::tuple as a parameter to constructor
int main(void) { Blob b1(5, "C++ Truths", 3, 99.99); } int main(void) { Blob b1(std::make_tuple(5, "C++ Truths"), std::make_tuple(3, 99.99)); }
![Page 39: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/39.jpg)
» Packing parameters into a tuple is easy
˃ Just call std::make_tuple
» Unpacking is easy too
˃ Use std::get<N>
int main(void) { std::tuple<int, double> t = std::make_tuple(3, 99.99); std::list<int> list (std::get<0>(t), std::get<1>(t)); }
» But the number and types of parameters may vary
» We need a generic way to unpack tuples
˃ This is extraordinarily complicated
![Page 40: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/40.jpg)
» If you have a tuple
t = (v1, v2, v3, …, vN)
» You need
get<0>(t), get<1>(t), get<2>(t), …, get<N-1>(t)
At Compile Time!
![Page 41: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/41.jpg)
» If you have a tuple
t = (v1, v2, v3, …, vN)
» And if you have another type
index_tuple<0, 1, 2, …, N-1>
» Use variadic templates to unpack a tuple
get<0>(t), get<1>(t), get<2>(t), …, get<N-1>(t)
At Compile Time!
Tuple Indices
![Page 42: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/42.jpg)
» We need some way to get index_tuple from a tuple
» E.g., index_tuple<0, 1, 2> from tuple(v1, v2, v3)
template <typename Tuple1, typename Tuple2, unsigned... Indices1, unsigned... Indices2> Blob(Tuple1 tuple1, Tuple2 tuple2, index_tuple<Indices1...>, index_tuple<Indices2...>) : _v(get<Indices1>(tuple1)...), _l(get<Indices2>(tuple2)...) { }
Any number of indices
Size of tuple must match # of indices
![Page 43: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/43.jpg)
» Use the one provided by your compiler!
˃ Not standard!
gcc Clang
Index Builder _Build_index_tuple __make_tuple_indices
Index Tuple _Index_tuple __tuple_indices
» Or write one yourself
˃ ~20 lines of template meta-programming
» Just Google!
![Page 44: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/44.jpg)
class Blob { template <typename Tuple1, typename Tuple2, unsigned... Indices1, unsigned... Indices2> Blob(Tuple1 tuple1, Tuple2 tuple2, index_tuple<Indices1...>, index_tuple<Indices2...>) : _v(get<Indices1>(tuple1)...), _l(get<Indices2>(tuple2)...) { } template <typename Tuple1, typename Tuple2> Blob(Tuple1 tuple1, Tuple2 tuple2) : Blob(tuple1, tuple2, typename make_indices<Tuple1>::type(), typename make_indices<Tuple2>::type()) {} }; int main(void) { Blob b1(std::make_tuple(5, "C++ Truths"), std::make_tuple(3, 99.99)); }
Using Delegated
Constructor
We don’t want users to pass the index_tuple
![Page 45: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/45.jpg)
» Avoid Copies
˃ std::make_tuple makes copies of parameters
» How do we perfect forward parameters through a tuple?
˃ Use std::forward_as_tuple
int main(void) { Blob b1(std::forward_as_tuple(5, "C++ Truths"), std::forward_as_tuple(3, 99.99)); }
std::tuple<int &&, double &&>
![Page 46: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/46.jpg)
class Blob { public: template <typename... Args1, typename... Args2> Blob(std::tuple<Args1...> tuple1, std::tuple<Args2...> tuple2) : Blob(std::move(tuple1), std::move(tuple2), typename make_indices<Args1...>::type(), typename make_indices<Args2...>::type()) {} private: template <typename... Args1, typename... Args2, unsigned... Indices1, unsigned... Indices2> Blob(std::tuple<Args1...> tuple1, std::tuple<Args2...> tuple2, index_tuple<Indices1...>, index_tuple<Indices2...>) : _v(std::forward<Args1>(std::get<Indices1>(tuple1))...), _l(std::forward<Args2>(std::get<Indices2>(tuple2))...) { } };
![Page 47: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/47.jpg)
» It does!
» “Piecewise Construct”; “Emplace Construct”
» In fact, standard library has a type called std::piecewise_construct_t
» The standard library uses this idiom in
˃ std::map
˃ std::unordered_map
˃ std::pair has a piecewise constructor!
![Page 48: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/48.jpg)
» Does it break encapsulation? ˃ Arguably, yes!
» The idiom should be used selectively ˃ Suitable for value-types implemented as structs (e.g., std::pair)
˃ When you know the implementation detail precisely
+ E.g., Auto-generated C++ lasses from DTD, XSD, IDL
![Page 49: C++11 Idioms @ Silicon Valley Code Camp 2012](https://reader035.vdocuments.mx/reader035/viewer/2022081403/554f53f3b4c905524c8b504a/html5/thumbnails/49.jpg)
» C++ Truths ˃ Rvalue References In Constructor: When Less Is More
˃ Perfect Forwarding of Parameter Groups in C++11
» A Sense of Design ˃ Efficient Argument Passing in C++11 (Parts 1, 2, and 3)
http://cpptruths.blogspot.com/2012/03/rvalue-references-in-constructor-when.html
http://codesynthesis.com/~boris/blog/2012/06/26/efficient-argument-passing-cxx11-part2
http://cpptruths.blogspot.com/2012/06/perfect-forwarding-of-parameter-groups.html