Skip to content

Archive

Tag: C++

Note: This is C++0x stuff and it’s really just an investigation into some of the more obvious parts of it, including the auto keyword and lambda functions as well as working with higher kinded types (signified in C++ as template-template parameters).

I’ve been doing a lot of Scala recently and have thus become quite spoiled by its awesomeness. It’s made me look at C++ again with a different eye – a more functional eye. I’ve been doing C++ for so long, that I forget about that functional style of programming, and I also forget just how bad C++ is at functional programming – when you’re a multi-paradigm language, it’s hard to be great at all the paradigms simultaneously.

So, I took a stab at writing a more “functional” map function. C++ provides the transform function template in the functional header file but I find it lacking because you have to pre-create the container that will be mapped-to. This is an attempt at creating that inside the map function.

First, we’ll need some header files:

#include <iostream>
#include <vector>
#include <list>
#include <string>
#include <functional>
#include <algorithm>
#include <iterator>
#include <boost/lexical_cast.hpp>

And now we can define the function.

template <typename InType,
  template <typename U, typename alloc = allocator<U>>
            class InContainer,
  template <typename V, typename alloc = allocator<V>>
            class OutContainer = InContainer,
  typename OutType = InType>
OutContainer<OutType> mapf(const InContainer<InType>& input,
                           function<OutType(const InType&)> func)
{
  OutContainer<OutType> output;
  output.resize(input.size());
  transform(input.begin(), input.end(), output.begin(), func);
  return output;
}

The idea is that the output container may be a different type of container from the input container and the output type may also be of a different type from the input type.

A really simple usage of this could be:

vector<int> v1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
auto v2 = mapf(v1, function<int(const int&)>([](const int& i) { return i + 9; }));

The reason it’s simple is that all it does is just take a vector of ints and map it to a vector of ints. That’s nothing flashy.

It’s more interesting if you do something like this:

auto v3 = mapf<float, vector, list>(
            mapf(
              mapf(v1, function<int(const int&)>([](const int& i) { return i + 9; })),
              function<float(const int&)>([](const int& i) {
                return i * 3.1415;
              })),
            function<string(const float&)>([](const float& i) {
              return string("\"" + lexical_cast<string>(i) + "\"");
            }));

This is the standard functional “chaining” we see with more fluid, immutable data structures. Futher, it is actually returning a list<string> instead of a vector<string>. In Scala (you could do something similar in Ruby or many other languages) this would be:

v1.map(_ + 9).map(_ * 3.1415).map(_.toString).toList

Now, I’m not exactly happy with what we’ve got here. It’s not that I can’t pimp the int and float types and thus make it more fluid (although that would be nice). It’s more that the template function specification is hideous. In order to actually use different output container types, you must specify too much in the template parameter list.

auto l1 = mapf<int, vector, list>(v1,
  function<int(const int&)>([](const int& i) { return i + 2; }));
copy(l1.begin(), l1.end(), ostream_iterator<int>(cout, "\n"));

Ideally we’d like to simply specify something like mapf<list>(...) instead. I need to work on this and see if I can come up with something nicer. Perhaps it’s as simple as wrapping it up with another function or a template class… when I get more time.

I made an enhancement to Protodef to allow for the ability to eliminate the namespace when pulling in the prototypes. So now you can make them look like this:

[cpp]
one::two::SomeClass::functionA()
{
}

one::two::SomeClass::functionB()
{
}
[/cpp]

… or this:

[cpp]
namespace one { namespace two {

SomeClass::functionA()
{
}

SomeClass::functionB()
{
}

} }
[/cpp]

(Protodef doesn’t put the namespace wrappers in for you – you would have done that by yourself. What it does do is allow you to skip putting in the one::two::.)

(NOTE: There’s a more up to date version of this in the General C++ Settings section.)

Finally! Vim’s decision to add a ‘shiftwidth‘ to everything I type when I’m inside a namespace is thoroughly annoying and there appears to be no “standard” way to fix this in Vim aside from writing your own function for use in the ‘indentexpr‘ option.

Well I finally got around to writing this up and, while extremely crude, it appears to work alright. You’ll find the function definition below as well as in the General C++ Settings section.

" Fix up indent issues - I can't stand wasting an indent because
" I'm in a namespace.  If you don't like this then just comment
" this line out.
setlocal indentexpr=GetCppIndentNoNamespace(v:lnum)

"
" GetCppIndentNoNamespace()
"
" This little function calculates the indent level for C++ and
" treats the namespace differently than usual - we ignore it.  The
" indent level is the for a given line is the same as it would
" be were the namespace not event there.
"
" This function is rather crude but it works.
"
function! GetCppIndentNoNamespace(lnum)
    let nsLineNum = search('^\s*\\s\+\S\+', 'bnW')
    if nsLineNum == 0
        return cindent(a:lnum)
    else
        let incomment = 0
        for n in range(nsLineNum + 1, a:lnum - 1)
            let cline = getline(n)
            if cline =~ '^\s*/\*'
                let incomment = 1
            elseif cline =~ '^.*\*/'
                let incomment = 0
            elseif incomment == 0
                if cline =~ '^\s*\S\+'
                    return cindent(a:lnum)
                endif
            endif
        endfor
        return cindent(nsLineNum)
    endif
endfunction

Switch to our mobile site