Topic: Const problem when instantiating function template


Author: tom_usenet@hotmail.com (tom_usenet)
Date: Fri, 21 May 2004 04:57:54 +0000 (UTC)
Raw View
On Mon, 17 May 2004 17:18:12 +0000 (UTC), stefan_heinzmann@yahoo.com
(Stefan Heinzmann) wrote:

>Hi all,
>
>I have disagreement between two compilers when deducing template
>parameters on instantiation of a function template and would like to
>know which compiler is right. The problem is related to a const
>qualification. Here's the code:

[SNIP]

Here's simplified version:

template <class T>
void f(T const& t);

int main()
{
  int const array[1] = {0};
  f(array);

  //What shoud T be deduced as in the call to f?
}

Well, during TAD (template argument deduction), P is the parameter
type (const T&) and A is the argument type (int const[1]). A is not
transformed since P is a reference type, but P is transformed to "T
const" (the referenced type is used, see 14.8.2.1/2).

So, we need to choose a T such that T const == int const[1]. Now, both
T = int const[1] and T = int[1] make the above true, since const
qualifying an array is equivalent to const qualifying the elements.

Comeau and VC 7.1 deduce T = int const[1] and GCC 3.3 deduces T =
int[1]. I really can't see anything in the standard to say which is
right, so perhaps this is a defect in the standard. Defect report
anyone?

Tom
--
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: stefan_heinzmann@yahoo.com (Stefan Heinzmann)
Date: Mon, 17 May 2004 17:18:12 +0000 (UTC)
Raw View
Hi all,

I have disagreement between two compilers when deducing template
parameters on instantiation of a function template and would like to
know which compiler is right. The problem is related to a const
qualification. Here's the code:

#include <algorithm>

// =============================================================
// Generic map element declarations.
// -------------------------------------------------------------

template<typename Elem> struct map_element_traits;

template<typename Elem> inline
const typename map_element_traits<Elem>::key_type&
key(const Elem& element)
{
     return map_element_traits<Elem>::key(element);
}

template<typename Elem> inline
const typename map_element_traits<Elem>::mapped_type&
mapped_value(const Elem& element)
{
     return map_element_traits<Elem>::mapped_value(element);
}

template<typename Elem>
struct key_value_compare
{
     typedef typename map_element_traits<Elem>::value_type vtype;

     bool operator()(const vtype& a, const vtype& b) const
     {
         return map_element_traits<Elem>::key(a)
              < map_element_traits<Elem>::key(b);
     }
};

// =============================================================
// Generic map declarations.
// -------------------------------------------------------------

template<typename Map> struct map_traits;

template<typename Map> inline
typename map_traits<Map>::const_iterator
begin(Map const& map)
{
     return map_traits<Map>::begin(map);
}

template<typename Map> inline
typename map_traits<Map>::const_iterator
end(Map const& map)
{
     return map_traits<Map>::end(map);
}

template<typename Map> inline
typename map_traits<Map>::const_iterator
find(Map const& m, typename map_traits<Map>::key_type const& k)
{
     return map_traits<Map>::find(m, k);
}

template<typename Map>
typename map_traits<Map>::mapped_type const&
lookup(         Map                          const& map,
        typename map_traits<Map>::key_type    const& key,
        typename map_traits<Map>::mapped_type const& def_value)
{
     typename map_traits<Map>::const_iterator i = find(map, key);
     return (i == end(map)) ? def_value : mapped_value(*i);
}

// =============================================================
// Types for lookup tables stored in ROM.
// -------------------------------------------------------------

template<typename Key, typename Val>
struct Pair
{
     Key key;
     Val val;
};

template<typename Key, typename Val>
struct map_element_traits< Pair<Key,Val> >
{
     typedef Pair<Key,Val>   value_type;
     typedef Key             key_type;
     typedef Val             mapped_type;

     static const key_type& key(const value_type& e)
         { return e.key; }
     static const mapped_type& mapped_value(const value_type& e)
         { return e.val; }
};

template<typename Key, typename Val, unsigned n>
struct map_traits< Pair<Key,Val>[n] >       //### const or not?
{
     typedef Key               key_type;
     typedef Val               mapped_type;
     typedef Pair<Key,Val>     value_type;
     typedef const value_type* const_iterator;

     static const_iterator begin(const value_type (&map)[n])
         { return &map[0]; }
     static const_iterator end  (const value_type (&map)[n])
         { return &map[n]; }

     static const_iterator find(const value_type (&map)[n]
                               ,const key_type& k)
     {
         value_type elem = { k };
         const_iterator i = std::lower_bound(begin(map), end(map)
                        , elem, key_value_compare<value_type>());
         return (i == end(map) || key(*i) != k) ? end(map) : i;
     }
};

// =============================================================
// Usage test
// -------------------------------------------------------------

const Pair<int, const char*> table[] =
{
     {     0, "Ok"                                      },
     {     6, "Minor glitch in self-destruction module" },
     {    13, "Error logging printer out of paper"      },
     {   101, "Emergency cooling system inoperable"     },
     {  2349, "Dangerous substances released"           },
     { 32767, "Game over, you lost"                     }
};

int main()
{
     const char *result = lookup(table, 5, "not found");
}


The problem is related to the struct map_traits. GCC 3.3 compiles the
code as shown, whereas VC++ 7.1 needs the marked line to be changed to this:

struct map_traits< const Pair<Key,Val>[n] >   //### const or not?

Obviously, the two compilers disagree when deducing the type of the
first argument to the lookup function template. Which one is right?

--
Cheers
Stefan

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]