Differences between compilers

This function will compile and operate perfectly with VS2010 and VS2008, but give an error with GNU GCC/g++ compiler:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <vector>
#include <iterator>
#include <algorithm>

// Returns the median of all elements in the range [first, last)
template <class Iter>
typename std::iterator_traits<Iter>::value_type
    Median(Iter first, Iter last)
{
    std::vector<std::iterator_traits<Iter>::value_type> arr( first, last );

    std::sort( arr.begin(), arr.end() );

    return arr.at( arr.size()/2 );
}


To make it compile, I had to add typename to line 10 like so:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <vector>
#include <iterator>
#include <algorithm>

// Returns the median of all elements in the range [first, last)
template <class Iter>
typename std::iterator_traits<Iter>::value_type
    Median(Iter first, Iter last)
{
    std::vector<typename std::iterator_traits<Iter>::value_type> arr( first, last );

    std::sort( arr.begin(), arr.end() );

    return arr.at( arr.size()/2 );
}


Which one is standard C++? What is the rule on this? How do I know that my code will work on any compiler?
Last edited on
AFAIK, typename is required before a qualified dependent name that refers to a type EDIT: that's used inside of a template, ofc.
value_type is a dependent name that refers to a type. Therefore, must be prefixed with typename.

The only way to be sure you code will work on every compiler is to either adhere to very strict C++ standards (and even then you might run into problems because some compilers might have more or less support for something than another. C++11, for example, has varying levels of support across compilers), or test compile your code on several different compilers.
Last edited on
closed account (zb0S216C)
The second code snippet is the correct one and it's the standard way.

The reason why you need a "typename" in that position is because "std::iterator::value_type" is a dependent name. Because templates are incomplete types before instantiation, the compiler cannot assume "std::iterator::value_type's" identity until "std::iterator" has been instantiated with some complete type. Because of the aforementioned, "typename" is used to tell the compiler in advance (prior to instantiation) that some nested symbol is in fact a type and not a piece of storage or function.

Wazzak
Last edited on
Ah excellent! Thanks for the info.

VS must have some additional disambiguation so it's good to know what I need to add to make it work on multiple compilers.

As a side note, and of interest, I recently found out that <cstdint> is not included in VS2008 despite being in C++11 and C99. VS2008 is not compliant with either standard. To make my code work there, I had to get rid of the useful uint32_t and replace it with a typedef of my own.
Ah, yeah. Visual studio didn't have stdint.h until VS2010. Although, you can copy an existing one into a VS2008 install if you feel like going the extra mile.
Visual Studio compilers are known for bending the rules a bit.
Topic archived. No new replies allowed.