Monday, November 12, 2007

What's wrong with Sun Studio C++?

Don't be surprised if you are using multimap and your code is working on other standard C++ compilers and not on Sun Studio C++. e.g. See below code, which is correct according to C++ standards, but it will not compile on Sun Studio C++.

And if you use map instead of multimap it will work. But hey, you want to use multimap and not map, so what's wrong with Sun Studio C++?

#include <map>
#include <utility>

int main() {
std::map<int, int> mymap;
mymap.insert(std::make_pair(2, 4));

std::multimap<int, int> mymultimap;
mymultimap.insert(std::make_pair(2, 4));

return 0;
}


If you compile this code with Sun Studio (my version was forte v10.0p1), you probably will get error something like,

Error: Could not find a match for std::multimap<int, int, std::less<int>, std::allocator<std::pair<const int, int>>>::insert(std::pair<int, int>) needed in main().


The same code will compile perfectly fine with other standard C++ compilers. So, what's wrong with Sun Studio C++? Is something missing in Sun Studio?

OK, So to investigate it further, if you open <sun-studio-installation-directory>/prod/include/CC/Cstd/utility, you'll find

#ifndef _RWSTD_NO_MEMBER_TEMPLATES
template <class U, class V> pair(const pair<U,V>& p)
: first(p.first), second(p.second)
{ ; }
#endif

and in <sun-studio-installation-directory>/prod/include/CC/Cstd/stdcomp.h, you'll find

# define _RWSTD_NO_MEMBER_TEMPLATES 1


Since _RWSTD_NO_MEMBER_TEMPLATES is defined, member template copy constructor is not available. In case of map class it has function

pair<iterator, bool> insert (const pair<key_type, mapped_type> &__x)
{
return insert (pair<const key_type, mapped_type> (__x.first, __x.second));
}

therefore it works for map class.

In case of multimap, value_type is pair<const Key, T>, and since pair class lacks the templated copy constructor, insert can't convert pair<int, int> to pair<const int, int>, So we can use following work around:
1.

#include <map>
#include <utility>

int main() {
std::map<int, int> mymap;
mymap.insert(std::make_pair(2, 4));

std::multimap<int, int> mymultimap;
mymultimap.insert(std::pair<const int, int>(2, 4));

return 0;
}

2.

#include <map>
#include <utility>

int main() {
std::map<int, int> mymap;
mymap.insert(std::make_pair(2, 4));

typedef std::multimap<int, int> intmultimap;
intmultimap mymultimap;

mymultimap.insert(intmultimap::value_type(2,4));
return 0;
}

3.
If you don't want to change your existing code, you can use more standard-conforming library, by specifying option -library=stlport4, while compiling and linking.

Sun C++ FAQs indicates that they cannot update the standard library without breaking source and binary compatibility, so they will continue to ship a libCstd with the same limitations. I hope these workarounds will help you then.

2 comments:

Kamaraju Kusumanchi said...

Thanks for the tip. It is useful!

dmytro said...

Thank you !