Knowledge Base/CPP/General

 

From Quantitative Finance

Jump to: navigation, search

Contents

Statically detecting the Visual Studio version

  1. #if _MSC_VER >= 1500
  2. // Visual Studio 2008 or above
  3. #elif _MSC_VER >= 1400
  4. // Visual Studio 2005
  5. #elif _MSC_VER >= 1310
  6. // Visual Studio 2003
  7. #elif _MSC_VER > 1300
  8. // Visual Studio 2002
  9. #endif

Convert an enum into an int. Convert an int into an enum

For enums, there is an implicit conversion to int:

  1. enum Quarter {FIRST=1, SECOND=2, THIRD=3, FOURTH=4};
  2. int q = FIRST;

For ints, there is an explicit conversion to enum:

  1. enum Quarter quarter;
  2. quarter = static_cast<Quarter>(2);

Testing an integer's even- or oddness

  1. if (n & 1) ...

Doubling a positive integer

  1. n <<= 1;

An algorithm for determining whether a function should be a member and/or friend

Use the following algorithm due to Herb Sutter and Andrei Alexandrescu to determine whether a function should be a member and/or friend (C++ Coding Standards: 101 Rules Guidelines and Best Practices, Item 44: Prefer writing nonmember nonfriend functions):

// If you have no choice then you have no choice; make it a member if it must be:
If the function is one of the operators =, ->, [], or (), which must be members:
        Make it a member.
// If it can be a nonmember *non*friend, or benefits from being a nonmember friend, do it:
Else if:
    a) the function needs a different type as its left-hand argument
       (as do operators >> and <<, for example);
 or b) it needs type conversions on its leftmost argument;
 or c) it can be implemented using the class's public interface alone:
        Make it a nonmember.
        If it needs to behave virtually:
            Add a virtual member function to provide the virtual behaviour,
            and implement the nonmember in terms of that.
Else
        Make it a member.

Implementing a non-const function in terms of the correpsonding const function

It is possible to implement a non-const function in terms of the corresponding const function as follows:

  1. const S & T::foo() const
  2. {
  3. // ...
  4. }
  5.  
  6. S & T::foo()
  7. {
  8. const T * cthis = this;
  9. return const_cast<T &>(cthis->foo);
  10. }

This technique, suggested by Siemel Naran, involves a const_cast.

Implementing the postfix operator++ in terms of a prefix operator++

  1. // Prefix
  2. T & operator++()
  3. {
  4. // ... Perform the increment ...
  5.  
  6. return *this;
  7. }
  8.  
  9. // Postfix
  10. const T operator++(int)
  11. {
  12. T temp = *this;
  13.  
  14. ++*this;
  15.  
  16. return temp;
  17. }

Notice that (int) is used to distinguish between the prefix and postfix versions of the operator.

Similarly for operator--:

  1. // Prefix
  2. T & operator--()
  3. {
  4. // ... Perform the increment ...
  5.  
  6. return *this;
  7. }
  8.  
  9. // Postfix
  10. const T operator--(int)
  11. {
  12. T temp = *this;
  13.  
  14. --*this;
  15.  
  16. return temp;
  17. }

Implementing operator= in terms of a (no fail) swap

The following definition of operator= in terms of a copy constructor and a no fail swap is idiomatic. swap is needed for a guaranteed commit. It must not fail. It must never throw exceptions.

  1. T & T::operator=(const T & rhs)
  2. {
  3. T temp(rhs);
  4. noFailSwap(temp);
  5. }

Implementing operator@ in terms of operator@=

Where @ is a binary operator such as +, *, etc. This is generally a very good idea, consistent with the Principle of Least Surprise.

The non-member case: operator@ and operator@= are non-members

  1. T & operator@=(T & lhs, const T & rhs)
  2. {
  3. // ...
  4.  
  5. return lhs;
  6. }
  7.  
  8. T operator@(T & lhs, const T & rhs)
  9. {
  10. // Note that lhs is taken by value
  11. return lhs @= rhs;
  12. }

The member case: operator@ and operator@= are members

  1. T & operator@=(const T & rhs)
  2. {
  3. // ...
  4.  
  5. return *this;
  6. }
  7.  
  8. T & operator@(const T & rhs)
  9. {
  10. T temp(*this);
  11.  
  12. temp @= rhs;
  13.  
  14. return temp;
  15. }

Implementing operator!=, operator>, operator<=, operator>= in terms of operator== and operator<

We want to enforce consistency and avoid code repetition. Therefore we define operator== and operator<...

  1. inline bool operator==(const T & lhs, const T & rhs)
  2. {
  3. // ...
  4. }
  5.  
  6. inline bool operator<(const T & lhs, const T & rhs)
  7. {
  8. // ...
  9. }

...then implement the remaining relational operators in terms of the above, as follows:

  1. inline bool operator!=(const T & lhs, const T & rhs)
  2. {
  3. return !(lhs == rhs);
  4. }
  5.  
  6. inline bool operator>(const T & lhs, const T & rhs)
  7. {
  8. return rhs < lhs;
  9. }
  10.  
  11. inline bool operator<=(const T & lhs, const T & rhs)
  12. {
  13. return !(rhs < lhs);
  14. }
  15.  
  16. inline bool operator>=(const T & lhs, const T & rhs)
  17. {
  18. return !(lhs < rhs);
  19. }

Erase-remove idiom

The erase-remove idiom is the best way to remove elements with a specific value from a contiguous-memory container (e.g. a vector, string, or queue).

  1. c.erase(remove(c.begin(), c.end(), 1666), c.end());

For lists, the remove member function is more efficient:

  1. c.remove(1666);

For associative containers one must use the erase member function:

  1. c.erase(1666);

The "swap" trick to lop off the empty (reserved) space at the end of a vector or string

  1. vector<Widget> v;
  2. string s;
  3.  
  4. // ...
  5. // Use v and s
  6. // ...
  7.  
  8. vector<Widget>(widgets).swap(v);
  9. string().swap(s);

Inserting a key-value pair into a map efficiently

  1. someMap.insert(map<T, U>::value_type(someT, someU));

Looking up an element in a map while avoiding default element insertion

If you use the subscript syntax to access a map element as follows

  1. string fooValue = someMap["foo"];

a new element will be inserted if the key "foo" is not already in the map. The corresponding value will be default-initialised. If you want to avoid this insertion, use the following:

  1. map<string, string>::iterator iter = someMap.find("foo");
  2. if (iter != someMap.end())
  3. {
  4. fooValue = iter->second;
  5. }

Inserting an element into a set if it does not already exist

If we need to insert a new element into a set provided it doesn't already exist in the set, and deal with the consequences if the element already exists, we can use the following paradigm:

  1. pair<set<string>::iterator, bool> status = someSet.insert("foo");
  2. if (! status.second)
  3. {
  4. // The element wasn't inserted as it already existed in the set
  5. // ...
  6. }

Inserting an element into a map if the key does not already exist

If we need to insert a new element into a map provided the key doesn't already exist in the map, and deal with the consequences if the key already exists, we can use the following paradigm:

  1. pair<map<string, string>::iterator, bool> status = someMap.insert(pair<string, string>("foo", "bar"));
  2. if (! status.second)
  3. {
  4. // The element wasn't inserted as the key already existed in the map
  5. // ...
  6. }

It is worth noting that if we had someMap["foo"] == "baz" before the above code was executed, someMap["foo"] would not be overwritten.

Passing arrays to functions that expect iterators

Suppose you have the following function:

  1. #include <iterator>
  2. #include <numeric>
  3.  
  4. template <typename _IterT>
  5. typename iterator_traits<_IterT>::value_type sum(_IterT from, _IterT to)
  6. {
  7. return accumulate(from, to, 0);
  8. }

You want to pass an array to it. You can do it as follows:

  1. template <typename _Data, typename _Size = size_t>
  2. _DataT sum(const _Data * data, Size N)
  3. {
  4. return sum(data, data + N);
  5. }

Adding up the element counts in a vector of vectors using std::accumulate and Boost lambda abstractions

Suppose that you have a collection of collections, e.g. a vector of vectors. You want to count all the elements in this structure (i.e. add up the sizes of the contained vectors). You can achieve this by using std::accumulate and Boost lambda abstractions:

  1. #include <iostream>
  2. #include <numeric>
  3. #include <vector>
  4.  
  5. #include <boost/lambda/bind.hpp>
  6. #include <boost/lambda/lambda.hpp>
  7.  
  8. using namespace std;
  9. using namespace boost::lambda;
  10.  
  11. void columnCountProto()
  12. {
  13. typedef vector<double> VectorOfDoubles;
  14. typedef VectorOfDoubles::size_type SizeType;
  15.  
  16. typedef vector<VectorOfDoubles> VectorOfVectorsOfDoubles;
  17.  
  18. VectorOfVectorsOfDoubles vectorOfVectors;
  19.  
  20. VectorOfDoubles v1;
  21. VectorOfDoubles v2;
  22. VectorOfDoubles v3;
  23. VectorOfDoubles v4;
  24. VectorOfDoubles v5;
  25.  
  26. v1.push_back(1.0); // 1
  27. v1.push_back(2.0); // 2
  28.  
  29. v2.push_back(3.0); // 3
  30. v2.push_back(5.0); // 4
  31. v2.push_back(7.0); // 5
  32.  
  33. v3.push_back(10.0); // 6
  34.  
  35. v5.push_back(0.0); // 7
  36.  
  37. vectorOfVectors.push_back(v1);
  38. vectorOfVectors.push_back(v2);
  39. vectorOfVectors.push_back(v3);
  40. vectorOfVectors.push_back(v4);
  41. vectorOfVectors.push_back(v5);
  42.  
  43. cout << "vectorOfVectors size: " << vectorOfVectors.size() << endl;
  44.  
  45. SizeType elementCount =
  46. accumulate(
  47. vectorOfVectors.begin(),
  48. vectorOfVectors.end(),
  49. SizeType(0),
  50. _1 + bind(&VectorOfDoubles::size, _2));
  51.  
  52. cout << elementCount << endl;
  53. }

This displays "7", as expected.

What about finding the maximum count, rather than the sum? Use the following code instead:

  1. SizeType maxElementCount = accumulate(
  2. vectorOfVectors.begin(),
  3. vectorOfVectors.end(),
  4. SizeType(0),
  5. bind(Maximum<SizeType>(),
  6. bind(&VectorOfDoubles::size, _2), _1));
  7.  
  8. cout << maxElementCount << endl;

This will display "3" (due to v2, which contains three elements).

By the way, here Maximum is defined as follows:

  1. template <typename _Type>
  2. struct Maximum : public binary_function<_Type, _Type, _Type>
  3. {
  4. _Type operator()(_Type first, _Type second) const
  5. {
  6. return (second > first) ? second : first;
  7. }
  8. };

Note that the Standard Library defines the two template functions std::min and std::max in the <algorithm> header, but Visual Studio C++ does not define these function templates as per Danny Kalev's comment. If std::max is available, you can use it instead of the Maximum above.

Remember that accumulate is defined in the header file <numeric>, not <algorithm>.

Along the same lines you can use for_each to clear the contained vectors in a vector of vectors:

  1. for_each(vectorOfVectors.begin(), vectorOfVectors.end(), bind(&VectorOfDoubles::clear, _1));

You can also reserve some space in all of them, say enough space for ten doubles:

  1. for_each(vectorOfVectors.begin(), vectorOfVectors.end(), bind(&VectorOfDoubles::reserve, _1, 10));

We can also construct a vector of iterators for the contained vectors, pointing to their first elements ("begin"):

  1. vector<VectorOfDoubles::iterator> vectorOfIterators;
  2.  
  3. transform(
  4. vectorOfVectors.begin(), vectorOfVectors.end(),
  5. back_inserter(vectorOfIterators),
  6. bind(boost::mem_fn(&VectorOfDoubles::begin), _1));
 
 
Google
 
Personal tools