Skip to content

c++

type introspection

Introspection is examining type information at runtime, reflection goes deeper and can also manipulate values, properties and functions at runtime.

C does not have reflection possibilities so this is about introspection, and in particular inspecting the types of runtime variables.

The main source for this came from : visit

Very basic you can get a code for any type with this command :

typeid
1
2
3
4
5
...
int main(int argc, char **argv) {
...
std::cout << typeid(main).name() << 'n';
...

It prints

signature
FiiPPcE

My guess after some playing around : it must be short for (F)unction returning (i)nt with parameters (i)nt and (P)ointer to (P)ointer to (c)har. The E is a mystery, it ios not external linkage, since static changes nothing. Maybe it is an end marker !?!

Use c++filt to decode these

These are mangled names, see : visit You need the -t (type) parameter for these :

reverse signature
++filt -t FiiPPcE
int (int, char**)

Note that without the E it just returns FiiPPc, so it might be an end marker after all ??

Note that const qualifiers will be gone in this method !!

Here is the description of the typeid operator. : visit which does not mention the codes so it must be a compiler specific operator since it suggests it prints the complete types.

However the discussion above lead to a very handy implementation that prints a readable typename like :

readable typename
1
2
3
std::cout << "decltype(i) is " << type_name<decltype(main)>() << 'n';
... gives 
decltype(i) is int(int, char**)

The complete implementation is this header file :

implementation
#include <cstddef>
#include <stdexcept>
#include <cstring>
#include <ostream>

#ifndef _MSC_VER
#  if __cplusplus < 201103
#    define CONSTEXPR11_TN
#    define CONSTEXPR14_TN
#    define NOEXCEPT_TN
#  elif __cplusplus < 201402
#    define CONSTEXPR11_TN constexpr
#    define CONSTEXPR14_TN
#    define NOEXCEPT_TN noexcept
#  else
#    define CONSTEXPR11_TN constexpr
#    define CONSTEXPR14_TN constexpr
#    define NOEXCEPT_TN noexcept
#  endif
#else  // _MSC_VER
#  if _MSC_VER < 1900
#    define CONSTEXPR11_TN
#    define CONSTEXPR14_TN
#    define NOEXCEPT_TN
#  elif _MSC_VER < 2000
#    define CONSTEXPR11_TN constexpr
#    define CONSTEXPR14_TN
#    define NOEXCEPT_TN noexcept
#  else
#    define CONSTEXPR11_TN constexpr
#    define CONSTEXPR14_TN constexpr
#    define NOEXCEPT_TN noexcept
#  endif
#endif  // _MSC_VER

class static_string
{
    const char* const p_;
    const std::size_t sz_;

public:
    typedef const char* const_iterator;

    template <std::size_t N>
    CONSTEXPR11_TN static_string(const char(&a)[N]) NOEXCEPT_TN
        : p_(a)
        , sz_(N-1)
        {}

    CONSTEXPR11_TN static_string(const char* p, std::size_t N) NOEXCEPT_TN
        : p_(p)
        , sz_(N)
        {}

    CONSTEXPR11_TN const char* data() const NOEXCEPT_TN {return p_;}
    CONSTEXPR11_TN std::size_t size() const NOEXCEPT_TN {return sz_;}

    CONSTEXPR11_TN const_iterator begin() const NOEXCEPT_TN {return p_;}
    CONSTEXPR11_TN const_iterator end()   const NOEXCEPT_TN {return p_ + sz_;}

    CONSTEXPR11_TN char operator[](std::size_t n) const
    {
        return n < sz_ ? p_[n] : throw std::out_of_range("static_string");
    }
};

inline
std::ostream&
operator<<(std::ostream& os, static_string const& s)
{
    return os.write(s.data(), s.size());
}

template <class T>
CONSTEXPR14_TN
static_string
type_name()
{
#ifdef __clang__
    static_string p = __PRETTY_FUNCTION__;
    return static_string(p.data() + 31, p.size() - 31 - 1);
#elif defined(__GNUC__)
    static_string p = __PRETTY_FUNCTION__;
#  if __cplusplus < 201402
    return static_string(p.data() + 36, p.size() - 36 - 1);
#  else
    return static_string(p.data() + 46, p.size() - 46 - 1);
#  endif
#elif defined(_MSC_VER)
    static_string p = __FUNCSIG__;
    return static_string(p.data() + 38, p.size() - 38 - 7);
#endif
}

It starts with getting constexpr and noexcept right for various compilers. We could just fill that in for gcc if we know them to come to a shorter version. Of course running it through the preprocessor works fine :

preprocess
gcc -E type.hpp

It reveals that all macros should be filled in g++.

macros
1
2
3
#define CONSTEXPR11_TN constexpr
#define CONSTEXPR14_TN constexpr
#define NOEXCEPT_TN noexcept

Also the way to print the current function in g++ is PRETTY_FUNCTION

This yields this output :

output
class static_string
{
    const char* const p_;
    const std::size_t sz_;

public:
    typedef const char* const_iterator;

    template <std::size_t N>
    constexpr static_string(const char(&a)[N]) noexcept
        : p_(a)
        , sz_(N-1)
        {}

    constexpr static_string(const char* p, std::size_t N) noexcept
        : p_(p)
        , sz_(N)
        {}

    constexpr const char* data() const noexcept {return p_;}
    constexpr std::size_t size() const noexcept {return sz_;}

    constexpr const_iterator begin() const noexcept {return p_;}
    constexpr const_iterator end() const noexcept {return p_ + sz_;}

    constexpr char operator[](std::size_t n) const
    {
        return n < sz_ ? p_[n] : throw std::out_of_range("static_string");
    }
};

inline
std::ostream&
operator<<(std::ostream& os, static_string const& s)
{
    return os.write(s.data(), s.size());
}

template <class T>
constexpr
static_string
type_name()
{
    static_string p = __PRETTY_FUNCTION__;
    return static_string(p.data() + 46, p.size() - 46 - 1);
}

The expression type_name() gives us the type of main. the decltype () operator can be used to declare a variable with the same type as the argument, or a reference if (()) is used, for instance :

decltype
1
2
3
int x=100;
decltype(x) y;          // means: int y
decltype((x)) z = &x;   // means: int &z so it has to be initialized.

So between the <> of the type_name template appears the type of the main function. Though the part of type_name template is never used it is still vital to the template.

If we step into type_name<>() you will see the type of main filled in :

gdb run
1
2
3
4
5
(gdb) s
type_name<int (int, char**)>() () at test.hpp:50
50              static_string p = __PRETTY_FUNCTION__;
(gdb) p __PRETTY_FUNCTION__ 
$1 = "constexpr static_string type_name() [with T = int(int, char**)]"

Here is where is coming into play, the template itself does not use it but PRETTY_FUNCTION obviously does : with T. It reflects the T in the template, try and alter it and you will see. (you will also see that the offset + 46 actually expects 1 letter, the output will be shifted)

So we have a string here with the name we want at position 46. Assigning it to a static_string makes it more portable i guess because the original answer did not us it but parsed the string up to the '=' character.

see : visit

bitsets

C++ has the bitset type for expressing bits like bitfields in C :

bitfields
1
2
3
4
5
6
7
8
9
#include <bitset>

std::bitset<8> bs = { 0b1100'1100 };

cout << sizeof(myset) << endl;
cout << myset << endl;
// prints
8
11001100

Note that sizeof(myset) is 8 BYTES, don't be fooled by thinking it is 8 bits. This is just the minimum size for a bitset (long int). You will see that std::bitset<64> is still 8 bits, 65 will take 16 :

number of bits/bytes
#include <iostream>
#include <bitset>

int main(int argc, char** argv)
{
    std::bitset<64> myset { 0b1100'1100 };
    std::bitset<65> bigset { 0b1100'1100 };

    std::cout << sizeof(myset) << std::endl;
    std::cout << myset << std::endl;
    std::cout << sizeof(bigset) << std::endl;
    std::cout << bigset << std::endl;
}   

Output is :

output
1
2
3
4
8
0000000000000000000000000000000000000000000000000000000011001100
16
00000000000000000000000000000000000000000000000000000000011001100

65 bits just do not fit in 8 bytes, so it needs two longs (16 bytes) and at the next wrap (129) it will become 24 bytes. So this does present a better solution for bit arrays, since you would have to name each field in a bitfield struct differently :

really 8 bits but named separately
struct BIT {
    unsigned char f1 : 1;
    unsigned char f2 : 1;
    unsigned char f3 : 1;
    unsigned char f4 : 1;
    unsigned char f5 : 1;
    unsigned char f6 : 1;
    unsigned char f7 : 1;
    unsigned char f8 : 1;
};

At the minimal advantage that this struct will be 1 bytes in size.

A bitset is only larger in granularity (8 bytes).

Besides that bitset offers some convenience functions like :

  • test()
  • set()
  • reset()
  • flip()

static member functions

If you get this error :

error: cannot declare member function to have static linkage

It means that you have also added static to the definition of the member function.

static member function
class class Foo
{
    static void Bar();
};
...

// WRONG !! remove static here !
static void Foo::Bar()
{
    ...
}

Strange choice, but just memorize that.

compilation error

It usually start with :

error
34 /usr/include/c++/9/bits/basic_ios.h:201 col 7: error: expected identifier before string constant

And it is on one of these lines in basic_ios.h

basic_ios.h
1
2
3
bool
fail() const
{ return (this->rdstate() & (badbit | failbit)) != 0; }

This usually means you have still included a c header like somewhere in your code. Either replace it or place it between :

check.h
1
2
3
extern "C" { 
#include <check.h>
}

compiler speedup

First of all, use make -j8 which makes make parallellize the make for 8 processors.

Or do make -j100 to make it use any processor available. To avoid having to alter .vimrc and to spare typing i made it an alias in.bashrc

alias for parallel make
alias make="/usr/bin/make -j 8"

Main reason not to use c++ was the tremendous time it takes to compile. Before my transition to c++ the backend library took 16 seconds to compile all versions :all: release debug test tags with clang++, and 14 seconds with g++

Afterwards it took 1m:08s, which is more than 6 times slower. One thing to try to speed it up was the use of precompiled headers. Start by looking at what a header files loads during compilation. Watch you make output and copy just one line, run it and time it :

timed run
1
2
3
4
5
time g++ -std=c++14 -I/usr/include/llvm-c-3.5 -I/usr/include/postgresql -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/uuid -I../lkh -I../3pty/osrm-backend/include -I../3pty/osrm-backend/third_party/variant/include -I../3pty/osrm-backend/third_party/flatbuffers/include -g -DDEBUG -DSTANDALONE -c osrm.cpp -o debug/osrm.o

real    0m2.597s
user    0m2.294s
sys     0m0.297s

Now look at what files it processes, with the -H flag :

list headers
1
2
3
4
5
6
7
. backend.h
.. /usr/include/c++/9/string
... /usr/include/x86_64-linux-gnu/c++/9/bits/c++config.h
.... /usr/include/x86_64-linux-gnu/c++/9/bits/os_defines.h
..... /usr/include/features.h
...... /usr/include/x86_64-linux-gnu/sys/cdefs.h
....... /usr/include/x86_64-linux-gnu/bits/wordsize.h

And many many more. Now you see it starts with backend.h which sucks in all the others, also backend is in a writable directory so try just compiling that file instead of the source file :

precompiled header
1
2
3
g++ -std=c++14 -I/usr/include/llvm-c-3.5 -I/usr/include/postgresql -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/uuid -I../lkh -I../3pty/osrm-backend/include -I../3pty/osrm-backend/third_party/variant/include -I../3pty/osrm-backend/third_party/flatbuffers/include -g -DDEBUG -DSTANDALONE -c backend.h 
ls backend.h*
backend.h  backend.h.gch

It just created a binary version of all that, you can first look at what header files now remain with the previous command, because it will take the h.ghc file before it takes the .h file (so make a makefile entry for that !!) The output is quit different :

output
! backend.h.gch
osrm.cpp
. /usr/include/c++/9/exception
. /usr/include/c++/9/iostream
. /usr/include/c++/9/string
. /usr/include/c++/9/utility
. /usr/include/c++/9/cstdlib
.. /usr/include/x86_64-linux-gnu/c++/9/bits/c++config.h
Multiple include guards may be useful for:
/usr/include/c++/9/cstdlib

It suggest include guards for certain files as well.

Also the timings are much better :

timed
1
2
3
real    0m1.168s
user    0m0.999s
sys     0m0.166s

I'll take that, it has halved. The total compile time now takes 54 seconds. If you examine the test/test.cpp compilation you will see that /usr/local/catch.hpp also drags in a lot of stuff but if you :

error
1
2
3
4
5
6
g++ -std=c++14 -g -DDEBUG -DSTANDALONE -DTESTING -I/usr/include/llvm-c-3.5 -I/usr/include/postgresql -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/uuid -I../lkh -I../3pty/osrm-backend/include -I../3pty/osrm-backend/third_party/variant/include -I../3pty/osrm-backend/third_party/flatbuffers/include /usr/include/catch.hpp 
# you get 
/usr/include/stdc-predef.h:1: fatal error: can’t create precompiled header /usr/include/catch.hpp.gch: Permission denied
1 | /* Copyright (C) 1991-2019 Free Software Foundation, Inc.
  | 
compilation terminated.

Also doing it as root does not work, so what if we put catch inside test/test.h. That does work, and it cuts down the time again. :

test/test.h
1
2
3
real    0m35.064s
user    0m29.727s
sys     0m5.229s

You can try out all lines that seem to take a longer time and find out if they are a target for precompilation.

The precompiled headers with different flags are not compatible like debug and release !!

It does seem to matter where you include the pch, the first line always works.

In fact the best strategy for speed compiles is to put all headers in one headers file and include that as the first line.

We are now down to (but for debug only !!!).

timed
1
2
3
real    0m10.552s
user    0m8.502s
sys     0m2.026s

Sadly i can't try a c run anymore for debug only

gch rejection

catch invalidates all .gch files you make !, i switched to google tests just for that reason.

You can see with the -H flag what headers are pulled in and also which are rejected :

Acceptation is marked with a !

-H output
1
2
3
! test/test.hpp.gch/debugexe.hpp
test/test.cpp
. test/../backend.hpp

Rejection is marked with an x :

rejections are marked x
x test/test.hpp.gch/debugobj.hpp
. test/test.hpp
.. /usr/include/gtest/gtest.h
... /usr/include/c++/9/cstddef
.... /usr/include/x86_64-linux-gnu/c++/9/bits/c++config.h
..... /usr/include/x86_64-linux-gnu/c++/9/bits/os_defines.h
...... /usr/include/features.h
....... /usr/include/x86_64-linux-gnu/sys/cdefs.h
........ /usr/include/x86_64-linux-gnu/bits/wordsize.h
........ /usr/include/x86_64-linux-gnu/bits/long-double.h

and that will go on for a while.

.gch files are only valid for compilation with the 'exact' same flags.

Exact is relative, some flags are compatible, but certainly -g and -o are not. You can easily make a .gch file for each of them by creating a directory .gch file instead of a file ! All files in that directory are then examined and the first one that works is used. The files can be any name you choose !!

const objects

When making a global object at least try to make it const, so nobody can mess with it. You can instantiate the object as const by declaring :

const objects
MyClass const myInstance;
# myInstance is a const (instance of) MyClass

However you will now get these errors if you do this on an unprepared class:

passing 'const Osrm' as 'this' argument discards qualifiers [-fpermissive]

The function in question was :

error
1
2
3
4
class Osrm {

public:
    coords_t nearest(coords_t xy);

What the error is saying is that you call myInstance.nearest(myxy) as :

calling myInstance.nearest(myxy) roughly does this
myInstance.nearest(Osrm *this=myInstance, coords_t myxy)

This roughly what a member call does, patching the object itself into 'this' as first parameter. Now you are assigning a const (myInstance) to a non-const (this) and that's not allowed. If you now declare the method as const :

const
coords_t nearest(coords_t xy) const;
# nearest is a const function returning coords_t

to read the declaration in plain text always start at the name and then first go right for specifiers and () or [] then leftwards.

You could now read the function as :

roughly means
myInstance.nearest(const Osrm *this, coords_t xy)

It does NOT also make the xy coords_t const !!. The const just says the function will not change the instance, and this it's variables. xy is just a local variable !!

In this way we can use the osrm pointer with having to pass it down in every function without any function accidentally changing it's state.

const linkage

const variables have internal linkage by default !!

As opposed to non-const variable which have external linkage by default.

example
# constant.cpp
int x = 11;             # ok, default external definition
int x;                  # ok, implicit definition int x=0;
const int y = 13;       # not ok, default static
extern const z = 15;    # ok

# main.cpp
extern int x            # extern needed to say it is defined somewhere else
extern const y;         # will fail !!
extern const z;         # ok !, it is a declaration 
extern const z = 14;    # not ok !! this makes it a (second) definition 

For an explanation, one anonymous comment put it very clear :

: This is because they are intended to be used like this:

usage
1
2
3
4
5
6
7
// a.cpp
const int BUFSIZE = 100;
char abuf[BUFSIZE];

// b.cpp
const int BUFSIZE = 256
int bbuf[BUFSIZE];

constant namespace

However, it also means that how i wanted to use it was to have a program-wide constant namespace that is the same for every source file.

const namespace
header.h:
namespace constants {
    const int x = 10;
} 

constants.cpp
namespace constants {
    const int x = 11;
} 

main.cpp
std::cout << constants::x << std::endl;

With internal linkage it means that the constants is just included in each file as if it was typed there. And you can give both another value, also you have to initialize both since it is a static const.

I you use extern, you will have to initialize one of them ! And it does not seem to matter which, the header or the .cpp file. Initializing 0 or more than one will give an error. Also the error is :

multiple definition of 'x'

Which suggests that the same mechanism for non-consts is used, and that the one with the initializer is regarded as the definition, and all the others as declarations. This also means the right place to initialize is the constant.cpp file :

constant.cpp
1
2
3
4
5
6
7
8
9
header.h:
namespace constants {
    extern const int x;
} 

constants.cpp
namespace constants {
    extern const int x=11;
} 

With const expressions the one with the initializer is the definition. In non-const the one without 'extern' is the definition.

initialization

coercion

Implicit type conversion in assignments and expressions can lead to weird results :

does NOT print -5
std::cout << 5u - 10;

This does not print -5, but 4294967291. This has to do with the rules of coercion

Evaluating arithmetic expressions

When evaluating expressions, the compiler breaks each expression down into individual sub expressions. The arithmetic operators require their operands to be of the same type. To ensure this, the compiler uses the following rules:

If an operand is an integer that is narrower than an int, it undergoes integral promotion (as described above) to int or unsigned int. If the operands still do not match, then the compiler finds the highest priority operand and implicitly converts the other operand to match. The priority of operands is as follows:

  • long double (highest)
  • double
  • float
  • unsigned long long
  • long long
  • unsigned long
  • long
  • unsigned int
  • int (lowest)

So in this case:

5u - 10 == with types : unsigned int - signed int == the highest priority wins, so 10 get's promoted unsigned int - unsigned int 5u - 10u = -5u == -5 unsigned wraps around to 4294967291

be careful with mixing signed and unsigned integers.

If in doubt you can use typeinfo to see what the type is. It might be worth noting that g++ uses these codes for the types :

  • signed int : i
  • unsigned int : j
typeid
1
2
3
4
5
6
7
8
#include <typeinfo>

std::cout << typeid(5u).name() << std::endl;
# prints j
std::cout << typeid(10).name() << std::endl;
# prints i
std::cout << typeid((5u - 10)).name() << std::endl;
# prints j

So both operands 5u and 10 fit into an unsigned, but the answer does not.

implicit blocks

When using an if statement with 1 line, it is actually replace with an implicit block statement. So :

implicit blocks
1
2
3
4
5
6
7
if (a==1) 
    printf("A is 1n");

# is equivalent to  
if (a==1) {
    printf("A is 1n");
}

However, you would expect that to be the same for statements inside a switch case, but it is not :

not equivalent
switch (a) {
    case 1:
        printf("A");
        printf(" is");
        printf(" 1n");
    break;
    default:
    break;
}

# is NOT equivalent to 
switch (a) {
    case 1:
    {
        printf("A");
        printf(" is");
        printf(" 1n");
    }
    break;
    default:
    { }
    break;
}

It is a subtle difference, but for some scope rules.

{} needed or not
int a = 11;

if (1==1)
    int a = 12; // this would not work without { }

printf("a is %dn", a);

switch (11) { 
    case 11:
        int a = 13; // this won't work
    break;
    case 12:
    {
        int a = 13; // this will !
    } 
    break;
    default:
    break;
} 
printf("a is %dn", a);

Also you can define variables inside the switch {} block, but you cannot initialize them.

no initialization within switch {} block
switch (11)  {
    int x; // allowed
    int x=11; // not allowed !

    case 11;
        x = 11; // now it's allowed 
    case 12;
        printf("%dn", x);  // and it's usable in falltrough
    break;
}

The error you get when you initialize int x=11; before case labels is :

jump cross
jump to case label
crosses initialization of ‘int x’

So this makes sense if a switch directly does a goto (jump) the label 11 it never reaches the initialization step. You will get similar errors when you goto or continue in a similar situation.

functions and arrays

Note that this does not generate an error :

no error !
#include <iostream>

int func(int a[14]) // a just 'decays' into int * !!
{
    printf("%pn", a);
    a[5] = 22;
    a[6] = 23;
    a[7] = 24;
    a[8] = 25;

    return 0;
}

//A simple regex test
int main()
{
    int a[5] = { 1,2,3,4,5};
    int b = 111;
    func(a);
    printf("a is %d, %dn", a[5], b);
}

This will print:

output
a = 22, 24

What happens is that this is the stack frame of main at the time of calling func

at function call
a = [1,2,3,4,5,?,?,?];  // aligned on 4 or 8 bytes
b = 22

The stack frame for func will be

stackframe
a = [1,2,3,4,5,?,?,?,?,?,?,?,?,?,?,?]; // 15 long

At return it will be altered to :

at return
a = [1,2,3,4,5,22,23,24,25,?,?,?,?,?,?,?]; // 15 long

nullptr

C define NULL as a macro for 0, but there is a better way using nullptr.

nullptr is also 0 but it has the correct type for the pointer you use it for. For instance this snippet :

nullptr
double* A = nullptr; char* B = nullptr;
cout << typeid(A).name() << 'n'; cout << typeid(B).name() << 'n';

Will print

output
Pd
Pc

And if you feed those to c++filt :

c++filt
1
2
3
4
c++filt -t Pd
double*
c++filt -t Pc
char*

Neat, whenever you encounter an old NULL, just replace it with nullptr.

Then there is also a std::nullptr_t version and that is type that is only capable of holding a nullptr. I cannot see the use for it however.

references

non-const references can (and must) only be initialized with non-const l values.

initialize
int x = 5;
int &ref = x;

But !!, const references can also be initialized with const l values but also r values !!

allowed
1
2
3
const int x = 5;
const int &ref1 = x;    // yep !
const int &ref2 = 6;    // ! Yep !

The last one is a bit weird because what address is it referencing. Look at this code :

explanation
1
2
3
4
5
6
int x = 5;
int &ref1 = x;
const int &ref2 = 3;

printf("%p %p (%d)n", &x, &ref1, (&ref1-&x));
printf("%p %p (%d)n", &x, &ref2, (&ref2-&x));

We print the addresses of the references and the distance to the first variable x. This prints :

output
0x7ffec87319d8 0x7ffec87319d8 (0)
0x7ffec87319d8 0x7ffec87319dc (1)

So the address of ref1 is the same as that of x, that is what to expect. But ref2 is definitely pointing to another variable on the stack, 1 after x, so i presume there is a temporary variable constructed for this on the stack frame. Normally r-values have 'expression scope' which means the 5 is destroyed as soon as int x = 5 terminated (x is now 5, but the =5 to create it has gone). The = 3 however get's an extended life span that matches that of it's reference.

pointers

x->y is syntactic sugar for (*x).y, so it dereferences the pointer to struct for you.

for (each) loops

It is NOT foreach it is just for with a different syntax.

for loop
int arr = { 1,2,3,4 };
for (int i: arr) cout << i << endl;
// but also directly : 
for (float i: { 1.1, 2.2, 3.3 }) cout << i << endl;

// or.. 
std::array<int, 10> a; // create array of 10
std::iota(a.begin(), a.end(), 1);  // fill with 1-10
for (int i: a) std::cout << i << std::endl;

// and also vectors 
std::vector<int> fibonacci = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 };
for (int i: fibonacci) std::cout << i << std::endl;

// it also works with linked lists : todo :

You cannot get the index of a for loop since it works on constructs like linked lists which don't have an index.

Use a counter or a normal loop if you need the index !

To also alter the elements we need to do it by reference :

by reference
for (int e: a) e = 10; // no effect :
for (int e: a) std::cout << e << std::endl; //1,2,3,4,5...
for (int &e: a) e = 10; // this will work
for (int e: a) std::cout << e << std::endl; // 10,10,10,10...

// this won't work because int * is not an int
for (int *e: a) e = 10; 
// also no success because e is a temporary variable
for (int e: a) *e = 10;
// certainly not this, because e is the element/not the index !!
for (int e: a) a[e] = 10;

Don't forget e is the element, NOT the index. That's why i used e instead of i this time.

for (each) does NOT work with pointers to arrays, because the size has to be known for the loop.

constexpr

constexpr is a const expression that must be initialized at compile time, while const can be deferred until runtime. This makes constexpr a better candidate for optimization.

Don't use const/constexpr to be a good boy, it also promotes optimizations, especially constexpr

Always use constexpr unless the compiler complains.

constexpr
int main(int argc, char **argv) {
    constexpr int N=argc; // error, this has to be a const

default parameters

If you use default parameters beware that you can only declare it once, so you have to choose between the forward declaration OR the function definition:

default parameters
1
2
3
4
5
6
7
8
9
/* header.h */
void printValues(int x, int y=10);

/* main.c */
void printValues(int x, int y=10) // error: redefinition of default argument
{
    std::cout << "x: " << x << 'n';
    std::cout << "y: " << y << 'n';
}

I always did it in the function, but it might be better in the header file because that is what potential users see first. This advantage disappears when you don't offer the code as an interface library.

In any case i would add the other one as a comment as well

comment default values
1
2
3
4
5
6
7
8
9
/* header.h */
void printValues(int x, int y =10);

/* main.c */
void printValues(int x, int y/*=10*/)
{
    std::cout << "x: " << x << 'n';
    std::cout << "y: " << y << 'n';
}

default parameters do not count in function overloading !

A clarifying example :

example
1
2
3
4
5
void printValues(int x);
void printValues(int x, int y=20);

// the compiler can't know what to call if you do 
printValues(10);

default parameters do not work with function pointers !!, the defaults are replaced at compile time if absent. You can't do that with dynamic function pointers.

So you will need to supply all parameters yourself !

works
void fnc(int a, int b=2, int c=3)
{
    printf("%d %d %dn", a, b, c);
}

int main(int argc, char **argv)
{
    fnc(10);     // 10 2 3
    //int (*f2)(int) = fnc;     // fails on type 
    void (*f2)(int,int,int) = fnc; // works

    //f2(20);    // fails -> too few arguments to function
    f2(20,2,3);  // works : 20 2 3

    return 0;
}

const classes

Note that if you make classes const, some public functions might also become const.

const class
class Something
{
public:
    int m_value;

    Something(int x): m_value(x) { }

    void setValue(int value) { m_value = value; }
    int getValue() { return m_value ; }
};

int main()
{
    const Something something(4); // calls non const constructor

    something.m_value = 5; // compiler error: violates const
    something.setValue(5); // compiler error: violates const
    int x = something.getValue(); // compiler error: violates const

    return 0;
}

Though getValue only reads it still get's the violates const error. It changes when you make that function const in the class itself.

const function returning int
// const after the name: so getValue is a const function returning int
int getValue() const { return m_value ; }

Now this will compile. Note that this 'trick' will not work in setValue() because that tries to alter a (now) const member which remains a const violation.

Make all readonly methods const, so they can remain to be used if you make a const object instance.

Constructors can not be const since they need to initialize their members, the language disallows constructors to be const.

This means the 'const Something something(4)' will just work and init to 4

It is possible to overload a function with it's const version. The const one will then be used for it's const instances.

So this works :

works
const std::string& getValue() const { return m_value; } // getValue() for const objects
std::string& getValue() { return m_value; } // getValue() for non-const objects

Note that it would not make a difference if it was not returning a reference, because it would just return a separate copy of the member. But constness is considered part of the signature so these functions are different.

virtual functions

When using pointers to member functions pointers to base classes are assignable to pointers of derived classes. Not the other way around, because 'a dog is an animal' but 'an animal is not necessarily a dog'

virtual functions
#include <string>
#include <iostream>

class A
{
public:
    int value;

    A(int a) { value = a; };
    void i_am() {
        std::cout << "Class A with value " << value << std::endl;
    }
};

class B : public A
{
public:
    B(int a) : A(a) {}
    void i_am() {
        std::cout << "Class B with value " << value << std::endl;
    }
};

class C : public B
{
public:
    C(int a) : B(a) {}
    void i_am() {
        std::cout << "Class B with value " << value << std::endl;
    }
};


int main()
{
    A a(10);
    B b(20);
    C c(30);

    a.i_am();
    b.i_am();
    c.i_am();

    A *ap = &c;   // C becomes a ptr to A, C is an A
    //B *bp = &a; // B is NOT an A, but more specific, so error

    ap->i_am();
 return 0;
}

This will print :

output
1
2
3
4
Class A with value 10
Class B with value 20
Class C with value 30
Class A with value 30

As you see the assigned pointer prints the value of C, it's body is a C. But an A should now nothing about B or C classes so it prints its own i_am() function.

Making a method virtual enables the search to bubble down to the most derived candidate it can find. That means if you add 'virtual' to the i_am() function of A you get :

call
1
2
3
4
5
6
7
8
9
class A { 
...
    virtual void i_am() {
...

Class A with value 10
Class B with value 20
Class C with value 30
Class B with value 30

So it bubbled down to the i_am() of class B, while still having the 'body' of C.Adding virtual to the i_am() of B, makes it go all the way down :

output
1
2
3
4
Class A with value 10
Class B with value 20
Class C with value 30
Class C with value 30

Of course for this to work the methods should have identical prototypes.

Note that virtual functions are resolved at runtime, and thus ..slower !!

templates

function templates are filled in by the compiler according to the calls in the program.

templates
#include <iostream>

using namespace std;

template <typename T>
extern T function(T a,T b)
{
    return a + b;
}

int main(int argc, char** argv)
{
    int *arr = new int[3]{6,7,8};

    cout << function(1.2,4.3);
    cout << function(1,4);

    cout << arr[1] << endl;
}

This program will generate 2 functions because function is called with two different types.

nm output
1
2
3
nm a.out | grep function
000000000000129a W _Z8functionIdET_S0_S0_
00000000000012b4 W _Z8functionIiET_S0_S0_

There is a slight difference in the signature (d vs i). But the compiler deduces how many of these are needed.

Not only typenames are eligible for parameterizing, but you then have to give more information :

num parameters
1
2
3
4
5
6
7
8
9
template <typename T, int N>
T function(T a,T b)
{
    return (a + b * N);
}

// this is no longer deducible by the compiler so :
cout << function<int,10>(1,4) << 'n';
cout << function<double,20>(1.2,4.3) << 'n';

These 2 will also generate different signatures, and also the number is reflected in there. So all combinations of all calls generates one function.

nm output
00000000000012a8 W _Z8functionIiLi10EET_S0_S0_
00000000000012c5 W _Z8functionIiLd20EET_S0_S0_

I would probably add the in the previous example as well to note that it is a template and what type i meant to use.

use
1
2
3
cout << function<int>(1,4) << 'n';
// note that below int will be used and the parameters become (1,4) 
cout << function<int>(1.2,4.3) << 'n'; 

cpplint

cpplint is a program that checks for visit. Since it is an automated tool and i have no real style preferences i adhere to cpplint, and use astyle to format (most of) it. Especially these rules cannot be formatted with astyle :

  • at least two space between
  • Extra space before last semicolon;
  • Line ends in whitespace.
  • Should have a space between // and comment

Besides that just create a filed called ~/.astylerc with this content :

~/astylerc
# 4 space indent
-s4
# Indent 'class' and 'struct' access modifiers, 'public:', 'protected:' and 'private:', one half indent.
-xG
# max 80 chars per line
-xC80
# Indent 'switch' blocks so that the 'case X:' statements are indented in the switch block. The entire case block is indented.
-S
# Do not retain a backup of the original file. The original file is purged after it is formatted.
#-n
# Don't break one-line blocks.
-O
# Don't break complex statements and multiple statements residing on a single line.
-o
# Attach a pointer or reference operator (*, &, or ^) to the variable name (right).
-k3
# Insert space padding after paren headers only (e.g. 'if', 'for', 'while'...).
-H
# Insert space padding around operators.
-p
# style 
style=google

And to indent a file run this inside vim :

astyle
:%!astyle

Zap compiler

One of the most annoying things about c++ programming is the slow compilation. Zap can really make an end to this.

Speeding up process :

Let's start with the normal compilation of the backend without any aid. We only compile debug + test, which is the most common compilation when developing. Also i will do these runs with and without parallel make :

zap
make clean cleanheaders
time make 

method precompiled -j 1 -j 8


gcc no 2m18.307s 0m29.374s zapcc 1st run no 0m23.991s 0m13.715s zapcc 1st yes 0m23.246s 0m13.100s zapcc 2nd run no 0m16.368s 0m4.918s

For some reason precompiled headers don't have any effect anymore ?!?! Investigate that some time, in the mean time 4 seconds is VERY good, and also we don't have to keep track of the precompiled headers anymore, you don't have to regenerate them when changing something.

install zap compiler

The source comes from : visit

Sadly the compilation of the zap compiler itself is not so fast :

compile the zap compiler itself
1
2
3
4
5
6
7
sudo apt-get install ninja-build
git clone https://github.com/yrnkrn/zapcc.git llvm
mkdir build
cd build
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_WARNINGS=OFF ../llvm
ninja
sudo ninja install

The whole idea of zap is to cache as much as possible. So a second compile will much faster that the first. Also a make clean does not mean really recompile everything. You need to kill the zapserver for that :

kill zap
ps -elf | grep zap
pkill zapcc