Port projects to new tools
- By Giuseppe Puoti
- gio 27 agosto 2015
At work we use to touch projects as few as possible. To me this lead to bad problems on long term. For example we use to not upgrade our tools. I mean we not adopt modern language standard, new GUI libraries or file formats until we really need to. This force us to do big, potentially risky, tech jumps.
Because I'm missing more and more new features in the C++ language (we use C++98) and IDEs, I've decided to investigate how much effort would be required to switch a quite complex project from VS2008 to VS2015. Here follows some note from my experience.
build upgrade
The solution conversion run clean apart from some warning reported int the conversion log. Nothing to concern about, just some deprecated features gone. This was the easiest part.
moved header
In the new standard, some declaration have moved to different files.
error C3861: 'inserter' not found
Here the question is, is it still in the STL/C++11? A quick look at cppreference.com shows that std::inserter is now declared in iterator header. The same happen to back_inserter and other iterators related stuffs. The simple solution was add #include <iterator>.
STL changes
The comitee has done a great ammount of work from the VS2008 days refining the STL specification. The result is some adaption required for our project to conform.
error C2678: '<<' binary operator not found
I get this error in a function with this shape:
void foo(std::ostringstream &info)
{
...
std::cerr << info << std::endl;
...
}
Solved this using an explicit string convertion from std::ostringstream using its method str(). Not really the a so great solution but it worked for me. The function above has become:
void foo(std::ostringstream &info)
{
std::cerr << info.str() << std::endl;
}
Then I get:
error C2668: 'std::mem_fun': ambiguous function reference
Here what went wrong is the resolution of const return type from no const return type version of mem_fun. I expected the resolution to happen based on the constantness of the parameter. But, because the parameter method has both const and unconst overload, it fail resolving the right overload. I solved this using a lambda instead of the mem_fun but had some doubt. After posting a question on reddit/r/cpp, were someone (who really knowns what he says) pointed out that the lamda solution was actually the one to follow even to help the optimizer to do its job.
std::bad_cast has no more a constructor accepting custom message so I removed the custom message.
Sorry for the error reformulation unfortunatly the italian version of VS actually translates also compiler output. I agree with this change, it force us not to use exception that (wrong way) but define our own specialization instead.
We defined a function copy_if that was not included in C++98 STL. Because now it is in the standard, it was duplicated and ambigous and caused compilation error. This was solved by erasing our implementation of copy_if.
Linker errors
Then I started to get errors from the Linker. How ungly are they!
The first I get was a Linker error claiming from mfc90.lib. It cannot find the library. This happened because of a static library created with the old IDE and linked (even if dinamically) to MFC I was linking into. Solved by converting also the library project to the new toolchain.
Then I get an error claiming for a wrong usage of remove_if. In fact, remove_if cannot be used on a container like set because keys are immutable and so the ranges cannot be modified.
We actually were using it in a wrong way or the VS2008 implementation was a bit more permissive. The problem was about the remove of all item with a certain property from the set. To solve I've defined the following erase_if helper function that work also on other kind of containers (at least vector and list).
template <typename ContainerT, typename PredicateT>
void erase_if(ContainerT& c, PredicateT& pred) {
ContainerT::const_iterator item = find_if(c.begin(), c.end(), pred);
while (item != c.end()) {
c.erase(item);
item = find_if(c.begin(), c.end(), pred);
}
}
Note
You should prefer the erase-remove idiom for the supported containers like vector as it is more efficient.
Conclusions
So what the required effort? The projects I used for my little test is the one I'm working on day basis for about 6 month. It is not particulary big bou it use few quite complex proprietary library that needed to be converted too. It took a couple of my holyday day so I not really worked so hard. Not that big effort at the end.