Re: Explicitly specializing std::min() on VC++ 2005 Express Edition



Matthias Hofmann wrote:
"Tom Widmer [VC++ MVP]" <tom_usenet@xxxxxxxxxxx> schrieb im Newsbeitrag news:eyKHNIkjHHA.4872@xxxxxxxxxxxxxxxxxxxxxxx

template <std::size_t N>
struct min_impl<char[N]>;
This specialization for non-const char[N] seems superflous, as minimum<T>() accepts a constant reference, so min_impl<T>::impl() will never see a non-const char[N].
Good point, though I think it's the other way around - char[N] is needed, but not char const[N].

When I spezialize as follows:

// Non-const version.
template <std::size_t N>
struct minimum_impl<char[N]>;

then I get an error when calling minimum_impl::impl<>() from within minimum<>() because the actual parameters are constant.

Interesting, I just tried that on VC2005 and got an error too (the same error?). The error is due to a compiler bug, but there's a very simple workaround, which is to drop the use of ?:.

template <std::size_t N>
struct minimum_impl<char[N]>
{
static char const (&impl(char const (&a)[N], char const (&b)[N]))[N]
{ if (std::strcmp(a, b) < 0)
return a;
return b; }
};

The problem is that VC2005 is ignoring 5.16/4 (about ?: ):
"If the second and third operands are lvalues and have the same type, the result is of that type and is an lvalue."

Instead, it is applying the lvalue-to-rvalue conversion (e.g. the array-to-pointer conversion) to the parts of the ?: expression, and thus trying to return a pointer where an array is expected.

On the other hand,
when I spezialize as follows:

// Const version.
template <std::size_t N>
struct minimum_impl<const char[N]>;

then the primary template is called, not the specialization. I found out that this is because there is a bug in your implementation of minimum<>(). It should look like this:

template <class T> inline
const T& minimum( const T& a, const T& b )
{
// Note the 'const' before 'T'.
return minimum_impl<const T>::impl( a, b );
}

That's a bit of an odd way of doing it, since it means you always have to specialize for const T, rather than T, as is usual.

C++ declaration syntax isn't very nice.

Indeed, that's why I am trying a typedef:

template <std::size_t N>
struct minimum_impl<const char[N]>
{
typedef const char( &ARG )[N];

static ARG impl( ARG a, ARG b )
{
// C2440 error here.
return std::strcmp( a, b ) < 0 ? a : b;
}
};

That looks much clearer, but on VC++ 2005 Express Edition, it does not work. I get a C2440 error for not being able to convert from 'const char*' to 'const char (&)[2]' in the return statement. Where does that 'const char*' come from?

See above. Just to be clear, this compiles and works on VC2005:

#include <cstring>

template <class T>
struct minimum_impl
{
static const T& impl(const T& a, const T& b);
// { return a < b ? a : b; } commented out to check correct one is
//being called.
};

template <std::size_t N>
struct minimum_impl<char[N]>
{
static char const (&impl(char const (&a)[N], char const (&b)[N]))[N]
{ if (std::strcmp(a, b) < 0)
return a;
return b; }
};

template <class T> inline
const T& minimum( const T& a, const T& b )
{
// Note no 'const' before 'T'.
return minimum_impl<T>::impl( a, b );
}

int main()
{
char foo[] = "hello";
char bar[] = "world";

minimum(foo, bar);
}

Tom
.



Relevant Pages


Loading