C++
Functions | Variables
test.cxx File Reference
#include "gtest/gtest.h"
#include <algorithm>
#include <filesystem>
#include <iomanip>
#include <iostream>
#include <ranges>
#include <string>
#include <string_view>
#include <list>
#include <type_traits>
#include <vector>
#include <future>
#include <exception>
#include <utility>
#include <numeric>
#include <thread>
#include <deque>
#include <optional>
#include <any>
#include <execution>
#include <map>
Include dependency graph for test.cxx:

Go to the source code of this file.

Functions

 TEST (cpp11, string_recipes)
 
 TEST (cpp11, range_based_for_loops)
 
 TEST (cpp11, const_everything)
 
 TEST (cpp11, classes_and_type_traits)
 
 TEST (cpp11, auto_type)
 
 TEST (cpp11, lambda_expressions)
 
 TEST (cpp11, threading)
 
 TEST (cpp11, exceptions)
 
 TEST (cpp11, brace_initialisers)
 
 TEST (cpp11, narrowing)
 
 TEST (cpp11, learn_the_standard_library)
 
 TEST (cpp11, call_once)
 
 TEST (cpp14, return_value_optimisation)
 
 TEST (cpp14, digit_separators)
 
 TEST (cpp17, optional_types)
 
 TEST (cpp17, heterogeneous_types)
 
 TEST (cpp17, filesystem)
 
 TEST (cpp17, parallel_execution_policy)
 
 TEST (cpp17, clamp_values)
 
 TEST (cpp17, compiler_attributes)
 
 TEST (cpp17, maybe_unused_attribute)
 
 TEST (cpp20, ranges_and_views)
 
 TEST (cpp20, reduce_and_accumulate)
 
 TEST (cpp20, deprecated_with_comment)
 
 TEST (cpp20, contains_for_associative_containers)
 

Variables

size_t bird_count = 0
 

Function Documentation

◆ TEST() [1/25]

TEST ( cpp11  ,
auto_type   
)

Type inference is a game changer. You can simplify complicated (or unknown) type declarations with auto, but it can be a balance of convenience over readability.

Quite an interesting proposition: if you declare everything auto then you cannot leave anything uninitialised.

Definition at line 303 of file test.cxx.

◆ TEST() [2/25]

TEST ( cpp11  ,
brace_initialisers   
)

There are many more ways to initialise and append to a container.

In C++17 the type of vector can be inferred from the init list.

Definition at line 420 of file test.cxx.

◆ TEST() [3/25]

TEST ( cpp11  ,
call_once   
)

Listen very carefully, I shall say this only once... if you get this reference then you are a senior dev. You can call things only once using statics and lambdas (IIFE); or, use the well-named Standard Library function.

Definition at line 502 of file test.cxx.

◆ TEST() [4/25]

TEST ( cpp11  ,
classes_and_type_traits   
)

Knowning that classes sometimes need a virtual destructor always seemed a bit nuanced and error prone. Now you can test it.

Not my rules but a common opinion: structs hold data; but if there's any funtionality, then it should probably be a class.

Initialise class members in the header, I prefer the trailing underscore rather than "m_member".

Rule of 5: If a class requires a user-defined destructor, a user-defined copy constructor, or a user-defined copy assignment operator, it almost certainly requires all five.

Use virtual at the top level and then override in derived classes It stops you accidentally changing the signature or somebody else removing the base method. Mark methods as final once you've fixed all the bugs.

Definition at line 238 of file test.cxx.

◆ TEST() [5/25]

TEST ( cpp11  ,
const_everything   
)

Not a modern feature, of course, but you should: make everything constant. You ought to be prefixing const as a matter of course and then removing it when you have to: it’s much easier to reason about code when the data are immutable. In an ideal world everything would be constant – like Haskell – but it’s a balance of reason and getting things done.

Definition at line 213 of file test.cxx.

◆ TEST() [6/25]

TEST ( cpp11  ,
exceptions   
)

A key feature of the language but I eschew adding exceptions to my own code; it's much easier to reason about errors where they occur.

Definition at line 408 of file test.cxx.

◆ TEST() [7/25]

TEST ( cpp11  ,
lambda_expressions   
)

Lambda expressions are like function pointers but with a much friendlier implementation. Call them like a regular function or pass them as a parameter; you can also define them in-place so you don't have to go hunting for the implementation.

Definition at line 360 of file test.cxx.

◆ TEST() [8/25]

TEST ( cpp11  ,
learn_the_standard_library   
)

The standard library often expresses intention much more eloquently than a regular for-loop. Note the namespace is omitted for the count_if parameters, see Koenig/argument-dependent lookup (ADL).

Definition at line 486 of file test.cxx.

◆ TEST() [9/25]

TEST ( cpp11  ,
narrowing   
)

Initialising a small type with a large type will generate an error if you use braces. You don't seem to be able to downgrade this a warning.

Definition at line 465 of file test.cxx.

◆ TEST() [10/25]

TEST ( cpp11  ,
range_based_for_loops   
)

I really find it painful to go back to old style for-loops. All those clumsy explicit iterator declarations can be cleaned up beautifully with auto; in fact, we can drop the iterators altogether and avoid that weird i dereferencing idiom. Note you don't have access to the current index (until C++2a), which isn't necessarily a bad thing if you have aspirations of parallelisation.

You can also pass a function object where you would a lambda to std::for_each, and do more complex things like store state between element But this does, of course, make parallelising the operation more complicated.

Definition at line 148 of file test.cxx.

◆ TEST() [11/25]

TEST ( cpp11  ,
string_recipes   
)

Common string manipulations so you don't get tempted to use a third-party library.

  • trim_whitespace
  • remove_control_characters
  • to_lowercase
  • to_uppercase
  • to_snakecase
  • get_file_name
  • get_file_extension
  • starts_with
  • ends_with
  • split_string
  • contains

Definition at line 10 of file test.cxx.

◆ TEST() [12/25]

TEST ( cpp11  ,
threading   
)

Threading gives you the promise of speed at the expense of reasoning, complexity and debugging. But they are much more intuitive now than the old POSIX library.

std::futures are particularly interesting and let you return the stuff you're interested in much more easily: define a routine as a lambda and run it in the background while the main routine gets on with something else; and when we're ready, we block to get the value.

Definition at line 385 of file test.cxx.

◆ TEST() [13/25]

TEST ( cpp14  ,
digit_separators   
)

If you're defining hardware interfaces then you'll probably have register maps defined as hexadecimals; using digit separators can help improve readability in some cases. You can even define things in binary if you like.

Definition at line 547 of file test.cxx.

◆ TEST() [14/25]

TEST ( cpp14  ,
return_value_optimisation   
)

The destructor is called only once despite the nested constructors: see copy elision.

Definition at line 526 of file test.cxx.

◆ TEST() [15/25]

TEST ( cpp17  ,
clamp_values   
)

This would've been really useful in a previous life but I've yet to use of it since! Documented as a reminder.

Definition at line 655 of file test.cxx.

◆ TEST() [16/25]

TEST ( cpp17  ,
compiler_attributes   
)

Tell the compiler you meant to follow through.

Definition at line 672 of file test.cxx.

◆ TEST() [17/25]

TEST ( cpp17  ,
filesystem   
)

C++17 has a perfectly good interface to the filesystem so you don't need to use something like Qt's QFile.

Definition at line 618 of file test.cxx.

◆ TEST() [18/25]

TEST ( cpp17  ,
heterogeneous_types   
)

std::tuple is like a pair but better, and offers arbitrary collections of heterogeneous types. You can retrieve values by index (which looks a bit odd) or even by type! I think it makes for quite strange code but you can hide much of it with auto.

std::any is a little better thought out.

Definition at line 590 of file test.cxx.

◆ TEST() [19/25]

TEST ( cpp17  ,
maybe_unused_attribute   
)

If a variable is not used in all cases, mark with an attribute. Often happens where things aren't compiled in release.

Definition at line 706 of file test.cxx.

◆ TEST() [20/25]

TEST ( cpp17  ,
optional_types   
)

Optional types overcome the problem of defining a "not initialised" value – say, -1 – hich will inevitably used to index an array and cause an explosion. Your functions can now effectively return a "no result".

Definition at line 567 of file test.cxx.

◆ TEST() [21/25]

TEST ( cpp17  ,
parallel_execution_policy   
)

Quite an exciting prospect in C++17 is parallelising existing for-loops simply by adding an execution policy parameter.

Definition at line 636 of file test.cxx.

◆ TEST() [22/25]

TEST ( cpp20  ,
contains_for_associative_containers   
)

Check a key exists without find or count. Feels much more natural than checking the end stop.

Definition at line 786 of file test.cxx.

◆ TEST() [23/25]

TEST ( cpp20  ,
deprecated_with_comment   
)

Mark things as deprecated before you remove them.

Definition at line 758 of file test.cxx.

◆ TEST() [24/25]

TEST ( cpp20  ,
ranges_and_views   
)

An opportunity to simplify all the begin/end code that's been written since C++11.

Definition at line 723 of file test.cxx.

◆ TEST() [25/25]

TEST ( cpp20  ,
reduce_and_accumulate   
)

There's no need to specify a starting value with reduce, but there are some important considerations.

https://blog.tartanllama.xyz/accumulate-vs-reduce/

Definition at line 739 of file test.cxx.

Variable Documentation

◆ bird_count

size_t bird_count = 0

Definition at line 525 of file test.cxx.