Edmund's blog

Writing code.

Overload by return type

In C++ it is possible to have two functions with the same name, as long as the arguments are different. This is called overloading.

1
2
void GetValue(std::string& str);
void GetValue(bool& flag);

But how about overloading by return type? Say that we want to be able to write the following code.

1
2
3
4
Test test("true");

std::string str = test.Value();
bool flag = test.Value();

Is that possible? Well, not directly. The language does not allow overloading by return type.

1
2
std::string Value();
bool Value();  // does not compile

The trick is to use a proxy class and then implement conversion operators.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Test
{
public:
    Test(const std::string& str) : m_str(str) {}

    std::string GetString() const { return m_str; }
    bool GetBool() const { return m_str == "true"; }

    class Proxy
    {
    public:
        Proxy(const Test* pObj) : m_pObj(pObj) {}

        // Conversion operators
        operator std::string() const { return m_pObj->GetString(); }
        operator bool() const { return m_pObj->GetBool(); }

    private:
        const Test* m_pObj;
    };

    Proxy Value() const { return Proxy(this); }

private:
    std::string m_str;
};

There is only one Value() function. It returns a proxy object. The proxy class implements one conversion operator for each return type. It all just works.

Reversed range-based for loop

With a range-based for loop you can easily iterate over all elements in a container.

1
2
3
4
std::list<int> items{1, 2, 3};

for (auto&& item : items)
    std::cout << item << ' ';
1
1 2 3

But what if you want to reverse iterate over the items?

1
2
3
4
#include "ReverseAdapter.h"

for (auto&& item : MakeReverse(items))
    std::cout << item << ' ';
1
3 2 1

The C++ standard library does not provide a reverse adapter, so we have to write our own. This one works for both const and non-const containers.

ReverseAdapter.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#ifndef REVERSE_ADAPTER_H
#define REVERSE_ADAPTER_H


template<class T>
class ReverseAdapter
{
public:
    ReverseAdapter(T& container) : m_container(container) {}
    typename T::reverse_iterator begin() { return m_container.rbegin(); }
    typename T::reverse_iterator end() { return m_container.rend(); }

private:
    T& m_container;
};

template<class T>
class ConstReverseAdapter
{
public:
    ConstReverseAdapter(const T& container) : m_container(container) {}
    typename T::const_reverse_iterator begin() { return m_container.rbegin(); }
    typename T::const_reverse_iterator end() { return m_container.rend(); }

private:
    const T& m_container;
};


template<class T>
ReverseAdapter<T> MakeReverse(T& container)
{
    return ReverseAdapter<T>(container);
}

template<class T>
ConstReverseAdapter<T> MakeReverse(const T& container)
{
    return ConstReverseAdapter<T>(container);
}


#endif  // REVERSE_ADAPTER_H

Migrate SourceSafe to Mercurial

If you are still using SourceSafe today then you should move away from it as soon as possible. SourceSafe is buggy, slow, and tends to corrupt its database. Microsoft stopped supporting it years ago. Mercurial is nice and friendly. It works well on Windows, and is open source.

With vss2hg you can convert a SourceSafe project to a Mercurial repository. The perl script was written by Andy Duplain. I made a bunch of small fixes to it. You can download it here.

I used the vss2hg script to convert a bunch of SourceSafe projects with more than ten years of history. The largest took 24 hours to convert. It is slow, but it works.

After you have installed ActivePerl, you can run it from the command line.

1
2
3
set ssuser=MyName
set sspwd=MyPassword
vss2hg.pl --ssrepo="\\MyServer\VSS" --sshome="C:\Program Files (x86)\Microsoft Visual SourceSafe" $/MyProject

You need to set the OS to the US date format, otherwise the script does not work.

It is possible to make updates after the initial conversion by using the command line options --migrate-latest and --resume. This works pretty well when no files have been deleted or renamed in SourceSafe. Otherwise you can manually edit the histories.txt file, and then re-run --resume. I use kdiff3 to check that there are only changes at the bottom.

1
2
3
vss2hg.pl --ssrepo="\\MyServer\VSS" --sshome="C:\Program Files (x86)\Microsoft Visual SourceSafe" --migrate-latest $/MyProject
kdiff3 atoms.txt.1 atoms.txt
vss2hg.pl --ssrepo="\\MyServer\VSS" --sshome="C:\Program Files (x86)\Microsoft Visual SourceSafe" --resume $/MyProject

Work around min and max macros

Here is another trick that I learned for Stephan Lavavej’s posts on reddit.

How can you work around those evil lowercase min and max macros that Microsoft defines, so that you can use the std::min and std::max template functions? Well, it turns out that you can put parentheses around them. Not beautiful, but it works.

1
2
3
int val1 = 13;
int val2 = 10;
int minVal = (std::min)(val1, val2);

Obviously, the best solution is to define NOMINMAX in your precompiled headers file.

1
#define NOMINMAX

Use auto&& for range-based for loops

I learned this trick from Stephan Lavavej’s proposal for ISO C++.

Using auto for range-based for loops is inefficient. It will copy each element out of the container.

1
for (auto elem : range)  // inefficient

Using auto& is efficient, and works with both const and non-const containers.

1
for (auto& elem : range)  // efficient

Alas, it does not work with iterators that return proxy objects, such as the infamous std::vector<bool>. You cannot bind a temporary object to a non-const reference.

The trick is to use auto&&. It works with both const and non-const containers, but also works with proxy objects. It is always correct and efficient!

1
for (auto&& elem : range)  // efficient, and works with proxy objects

Initializing a struct

This is how a lot of people initialize their plain old data structs.

1
2
3
4
5
6
7
8
9
struct MyStruct
{
    double first;
    int second;
    char third[4];
};

MyStruct my;
memset(&my, 0, sizeof(my));

That memset is a lot of typing. Isn’t there a simpler way?

1
2
3
4
5
6
7
MyStruct my1;               // uninitialized
MyStruct my2 = { 2.0 };     // partially zero-initialized
MyStruct my3 = {};          // completely zero-initialized
MyStruct my4 = MyStruct();  // zero-initialized

MyStruct my5();  // function declaration (oops!)
MyStruct my6{};  // uniform initialization (C++11)

Note the partial initialization of my2. The remaining fields are zero-initialized.

My favorite way is my3. It almost looks like my6, but it doesn’t require C++11.

What about creating structs on the heap?

1
2
MyStruct* pMy1 = new MyStruct;    // uninitialized
MyStruct* pMy2 = new MyStruct();  // zero-initialized

Those parentheses make a huge difference!

Static data is always initialized.

1
static MyStruct s_my;  // zero-initialized

How about arrays?

1
2
3
4
5
6
7
MyStruct arr1[5];       // uninitialized
MyStruct arr2[5] = {};  // zero-initialized

MyStruct* arr3 = new MyStruct[5];    // uninitialized
MyStruct* arr4 = new MyStruct[5]();  // zero-initialized

std::vector<MyStruct> vec(5);  // zero-initialized

Like all STL containers, std::vector always initializes its data.

Getting the size of an array

How do you get the size of an array? This old fashioned method works.

1
2
3
4
5
6
7
#define COUNTOF(array) (sizeof(array) / sizeof(*array))

const char str1[] = "Hello";
size_t len1 = COUNTOF(str1);  // -> 6

const char *str2 = "Hello";  // BAD!
size_t len2 = COUNTOF(str2);  // -> 8

But if you don’t declare the array properly then things go horribly wrong. Never declare arrays as pointers!

The following C++ template function is much nicer. It does not compile at all when the array is declared as a pointer.

1
2
3
4
5
6
7
8
9
10
11
template<class T, size_t N>
size_t countof(const T (&)[N])
{
    return N;
}

const char str1[] = "Hello";
size_t len1 = countof(str1);  // -> 6

const char *str2 = "Hello";  // BAD!
size_t len2 = countof(str2);  // does not compile

The countof function takes a reference to an array and returns its size. It is a compile-time constant.

Passing an array by reference

How do you pass an array by reference in C++?

Like this:

1
2
3
4
5
6
7
void CallMe(const char (&array)[6]);

CallMe("Hello");

// These will not compile
CallMe("Hell");
CallMe("Hellos");

This way you can enforce an exact array size. Any other length will simply fail to compile.

Character pointer versus array

What is the difference between const char * and const char []?

Let’s run some code to see.

1
2
3
4
5
const char str1[] = "Hello";
size_t len1 = sizeof(str1));  // -> 6

const char *str2 = "Hello";
size_t len2 = sizeof(str2));  // -> 8 (BAD!)

The first one returns the actual size of the string, which is 6 characters including the null terminator. The second one returns the size of a pointer, 8 bytes or 64 bits.

The second notation throws away information. Strings should always be declared as arrays so that their size is known.