about
CppBits
10/14/2022
CodeBits Repo Docs

C++ Bits

organized bits of syntax, idoms, and patterns

Quick Status Recent page additions getting started testing UI format for code comparison will replace Idioms and Patterns UI layout now stable, needs more planned content
Bits are small compilable pieces of code that illustrate syntax, idioms, and small patterns. They support learning a new language by comparing bits with those of a language you already know. For now, that is limited to the programming languages C++, Rust, and C#. You can compare These C++ bits with C# or Rust bits using the navigation buttons below for each bit. If you have a wide screen or dual monitors you can right click on either of the show buttons and select "Open Link in New Window" to compare the Bits for two languages side-by-side.
C++ code bits
What is this?Code demoCommentary
Hello World
The traditional first look at a new language
// Hello.cpp #include <iostream> int main() { std::cout << "\n Hello World from C++" << "\n\n"; } C++ functions begin with a specific return type or keyword auto that uses type inference to decide the function's return type. They accept arguments in a parentisized list, encapsulate an executable code in a set of statements enclosed in braces, and infrequently declare a return type. auto g(ArgType a) -> ReturnType { ... } Each executable C++ program starts in a "main" function, which often calls other functions supplying operational details. There can be only one main in an executable.
Hello Objects
Demonstrates how Types are defined and instances created. The type DemoObj is defined above its main function and instances dob and cln are created in main.
// CppObject::CreateObj.cpp #include <iostream> #include <string> class DemoObject { public: DemoObject(const std::string& name) : name_(name) {} std::string name(); static void about(); private: std::string name_; }; std::string DemoObject::name() { return name_; } void DemoObject::about() { std::cout << "Demos creation and use of objects"; } int main() { DemoObject dob("Zing"); std::cout << "Created DemoObject instance with name " << dob.name(); /* create clone using compiler gen copy ctor */ DemoObject cln = dob; std::cout << "\nCreated DemoObject clone with name " << cln.name(); std::cout << "\n"; DemoObject::about(); std::cout << "\nThat's all Folks" << "\n\n"; } Types are defined with classes, like DemoObj on the left. Functionality is provided through methods, e.g., functions associated with the class. Methods may be defined inline within the class declaration, or separately with declarations that include the class name.
The method DemoObj(const std::string& name) is a constructor method that creates an instance of DemoObj and endows it with a name, passed as a std::string&. The :name_(name) suffix explicitly constructs the private DemoObj::name_ field. Method std::string DemoObject::name() is a method that implicitly accepts a reference to its instance and returns its name.
Methods that have a "static" prefix do not take an implicit reference to self and so cannot access member data. They act like ordinary functions but are accessed with their type followed by colons followed by the function. Non-static functions take an implicit reference to self, can access member data, and are accessed from an object name followed by a period.
Types and functions declare public accessibility within regions of the class declaration marked public. Functions declare return types with the -> SomeType syntax following the parameter list. auto f(T t) -> U { ... } The code at the left declares the type and operations for DemoObj. C:\...\CreateObject\CppObject> cd build C:\...\CreateObject\CppObject\build> cmake .. >NULL C:\...\CreateObject\CppObject\build> cmake --build . >NULL C:\...\CreateObject\CppObject\build> "./debug/CreateObj.exe" Created DemoObject instance with name Zing Created DemoObject clone with name Zing Demons creation and use of objects That's all Folks
Hello Data
This section demonstrates data binding, copy, and move operations for primitive and one typical composite type, the std::vector. For primitive types like int and float, construction and assignment are essentially identical for C++, Rust, and C#. Copy, assign, and move operations for composite types like std::vector and std::string implicitly invoke copy and move constructors and copy and move assignment operators. If not defined by the class, they are compiler-generated.
References:
CppStory_Classes
/* DataOps.cpp - demo data operations */ #include <iostream> #include <vector> #include <string> template <typename Coll> void show( const Coll& c, const std::string& msg = "" ) { std::cout << "\n "; if(msg.length() > 0) { std::cout << msg << " "; } using ValType = typename Coll::value_type; for(ValType item : c) { std::cout << item << " "; } } int main() { std::cout << "\n -- demo data operations --\n"; /* Primitive data types: int, double, ... occupy contiguous regions of memory, so copies simply copy memory. */ std::cout << "\n -- integer ops --"; int x = 42; auto y = x - 2; // copy construction std::cout << "\n x = " << x << ", y = " << y; x = y; // copy assign std::cout << "\n after copy assign: x = y"; std::cout << "\n x = " << x << ", y = " << y << "\n"; /* Most non-primitive types: Vec<T>, String, ... occupy memory on stack and heap, so they do not satisfy copy trait, so need copy ctor and copy assign operations. These often, but not always, can be correctly built by compiler, as needed. */ std::cout << "\n -- Vec ops --"; std::vector<int> v { 1,2,4 }; show(v, "v = "); auto w = v; // copy assign - a clone std::cout << "\n after copy construction: let w = v:"; show(v, "v = "); show(w, "w = "); std::cout << "\n set w[1] = -2"; w[1] = -2; show(v, "v = "); show(w, "w = "); // move construction from temporary std::vector<int> vm = std::vector<int> { 1,2,3 }; std::cout << "\n move construction: vector<int>: "; show(vm); std::cout << "\n\n That's all Folks!!\n\n"; } For composite types like std::string and std::vector, construction, copy, and assignment are very different for the three languages C++, Rust, and C#. C++ handles these operations with methods defined by the class or are compiler generated. See the reference cited in the left panel. -- demo data operations -- -- integer ops -- x = 42, y = 40 after copy assign: x = y x = 40, y = 40 -- Vec ops -- v = 1 2 4 after copy construction: let w = v: v = 1 2 4 w = 1 2 4 set w[1] = -2 v = 1 2 4 w = 1 -2 4 move construction: vector: 1 2 3 That's all Folks!! The compiler chooses which constructor to call, e.g., copy or move, based on the program context. Constructions are copy unless the source is a temporary. These context dependencies make C++ more difficult to learn and to apply consistently.
Iteration
Iteration is the process of stepping through a collection and, perhaps, doing something with each item encountered. This demo iterates over strings, string views, arrays, and array views. C++20 views are similar to Rust slices. The demos use std::iterator and range-based for loops.
This code needs to be compiled for C++20. The gcc option is --std=c++20.
#include<string> #include<ranges> #include<iostream> #include <locale> #include <algorithm> #include <string_view> #include <typeinfo> #include <iterator> #include <vector> /*-- helper function --*/ void putln(size_t num = 1) { for(size_t i=0; i<num; ++i) std::cout << "\n"; } /*-- basic string iteration demos --*/ void string_iteration() { std::string test_string = "a test string"; std::cout << "\n ascii characters from " << test_string << "\n "; std::string::iterator iter = test_string.begin(); while(iter != test_string.end()) { char ch = *iter; std::cout << ch << " "; if(iter == test_string.end()) break; ++iter; } std::cout << "\n test_string: " << test_string; putln(); } /*-- idiomatic string iteration demos --*/ void idomatic_string_iteration() { std::string test_string = "another test string"; std::cout << "\n idiomatic ascii chars from:\n " << test_string << "\n "; for(auto ch : test_string) { std::cout << ch << " "; } putln(); char ch2 = test_string[1]; std::cout << "\n 2nd character of " << test_string << " is " << ch2; std::cout << "\n test_string: " << test_string; putln(); } /*----------------------------------------------- demonstrate all_of(...), is_alphabetic, is_..., ranges, and string_view. */ /*-- helper function show collection items --*/ template<typename C> void put_coll( C& coll, const std::string& prefix = "" ) { std::cout << prefix; for(auto item : coll) { std::cout << item; } } /*-- helper function, displays test results --*/ void test( bool pred, const std::string& src, const std::string& category ) { if(pred) { std::cout << "\n " << src << " is " << category; } else { std::cout << "\n " << src << " is not " << category; } } /*-- demonstrate string adapter functions --*/ void string_adapters() { std::string ls = "abc123"; /*-- are all chars alphbetic --*/ auto is_alpha = [](char ch) -> bool { return std::isalpha(ch); }; test( std::all_of(ls.begin(), ls.end(), is_alpha), ls, "alphabetic" ); /*-- are all chars alphanumeric --*/ auto is_alnum = [](char ch) -> bool { return std::isalnum(ch); }; test( std::all_of(ls.begin(), ls.end(), is_alnum), ls, "alphanumeric" ); /*-- are all chars ascii --*/ auto is_ascii = [](char ch) -> bool { return 0 <= ch && ch < 128; }; test( std::all_of(ls.begin(), ls.end(), is_ascii), ls, "ascii" ); /*-- are all chars numeric --*/ auto is_num = [](char ch) -> bool { return std::isdigit(ch); }; test( std::all_of(ls.begin(), ls.end(), is_num), ls, "numeric" ); putln(); /*-- using range::view with pipe --*/ auto r = ls | std::views::filter(is_num); put_coll(r,"\n r is "); /*-- numeric if numeric range, r, is same size as ls --*/ test( std::distance(r.begin(), r.end()) == ls.size(), ls, "numeric" ); putln(); /*-- display chars from str slice --*/ ls = "abc123"; /*-- non-owning view --*/ std::string_view slice{ ls }; slice.remove_prefix(2); slice.remove_suffix(2); std::cout << "\n third and fourth chars of " << ls << " are " << slice; put_coll(slice, "\n slice is "); std::cout << "\n ls is still " << ls; putln(); /*--------------------------------------------- Form string from numeric chars in source, ls. Uses std::range adapter std::view. */ auto results = ls | std::views::filter(is_num); std::cout << "\n numeric chars of " << ls << " are "; for(auto r:results) { std::cout << r; } put_coll(results, "\n "); /*--------------------------------------------- The results item has a very ugly type. Uncomment lines below to see it. That means that std::cout << results; will fail to compile. */ // std::cout << typeid(results).name(); putln(); } /*----------------------------------------------- Define and iterate through byte array */ using byte = short int; using Iter = byte*; void define_and_iterate_byte_array() { byte ba[] = { 1, 2, 3, 4, 5 }; std::cout << "\n "; for( Iter it=std::begin(ba); it != std::end(ba); ++it ) std::cout << *it << " "; putln(); } void idiomatic_define_and_iterate_byte_array() { short int ba[] = { 1, 2, 3, 4, 5 }; std::cout << "\n "; for(auto i : ba) { std::cout << i << " "; } put_coll(ba, "\n "); putln(); std::cout << "\n ["; auto temp = ba | std::views::take(4); for(auto i : temp) { std::cout << i << ", "; } auto iter = std::end(ba); auto last = *(--iter); std::cout << last << "]"; } int main() { std::cout << "\n -- demonstrate iteration --\n"; std::cout << "\n -- string iteration --"; string_iteration(); idomatic_string_iteration(); std::cout << "\n -- string iteration adapters --"; string_adapters(); std::cout << "\n\n -- byte array iteration --"; define_and_iterate_byte_array(); std::cout << "\n -- idiomatic byte array iter'n --"; idiomatic_define_and_iterate_byte_array(); std::cout << "\n\n That's all Folks!\n\n"; } Unlike Rust, which uses utf8 characters that range in size from 1 to 4 bytes, C++ characters are 1 byte for std::char and 2 bytes for std::w_char. Since it has fixed size characters, iteration over strings use the same processes as for arrays and vectors. -- demonstrate iteration -- -- string iteration -- ascii characters from a test string a t e s t s t r i n g test_string: a test string idiomatic ascii chars from: another test string a n o t h e r t e s t s t r i n g 2nd character of another test string is n test_string: another test string -- string iteration adapters -- abc123 is not alphabetic abc123 is alphanumeric abc123 is ascii abc123 is not numeric r is 123 abc123 is not numeric third and fourth chars of abc123 are c1 slice is c1 ls is still abc123 numeric chars of abc123 are 123 123 -- byte array iteration -- 1 2 3 4 5 -- idiomatic byte array iter'n -- 1 2 3 4 5 12345 [1, 2, 3, 4, 5] That's all Folks!
Data Structures
Functions
Generic functions
Structs
Generic structs
Basic DIP
Generic DIP
 
  Next Prev Pages Sections About Keys