Boost logo

Boost :

Subject: Re: [boost] MSVC9 SFINAE quirks?
From: Simonson, Lucanus J (lucanus.j.simonson_at_[hidden])
Date: 2009-01-13 22:59:17


-----Original Message-----
From: boost-bounces_at_[hidden] [mailto:boost-bounces_at_[hidden]] On Behalf Of Steven Watanabe
Sent: Monday, January 12, 2009 4:26 PM
To: boost_at_[hidden]
Subject: Re: [boost] MSVC9 SFINAE quirks?

AMDG

Simonson, Lucanus J wrote:
> Maybe I shouldn't have used the word literal. It is a constant looked up by metafunction, of course.
>
> I was talking about different possible implementations for enable_if having different behaviors when compiled in MSVC.
>
> I don't know, but I would guess that the order of evaluation of template parameters separated by the comma operator is not defined by the standard?
>

I believe not.

> A syntax error in the instantiation of some_template<T> might lead the compilation to fail before trying to instantiate and_, I don't know. It seems that this is the case with MSVC some of the time.
>

The point is that the compiler doesn't know that some_template<T> needs
to be instantiated
until after it has gone through the SFINAE. I know that earlier
versions of msvc would sometimes
instantiate templates too soon, but I don't know

> The boost implementation of enable_if works well with MSVC. The alternative 1:
>
> template <typename T, tyepname T2>
> struct enable_if_T { typedef T2 type; };
> template <typename T2>
> struct enable_if_T<false_type, T2> {};
>
> does not behave as expected (and as in gcc) when parsed by MSVC.
>
> The alternative 2:
>
> template <typename T, tyepname T2>
> struct enable_if_T {};
> template <typename T2>
> struct enable_if_T<true_type, T2> { typedef T2 type; };
>
> results in yet another behavior from MSVC, specifically the problem above, whereas alternative 1 resulted in ambiguous function syntax errors in many cases rather than the expected SFINAE overloading semantic.
>
> Boost's implementation of enable_if:
>
> template <typename T, typename T2>
> struct enable_if : enable_if_c<T::value, T2> {};
>
> converts it from a template on type to a template on the constant specified by value. This seems to impact the order of template instantiation as well as the assumptions MSVC makes about whether SFINAE should apply.
>

Steven wrote:
>It's really a case of msvc taking SFINAE too far. If you only have a
>single function template,
>you can either get an ICE or bizarre runtime behavior. At the moment, I
>can't reproduce your
>problem, nor can I reproduce the ICE...

Sorry, I should have given you something better to test with. The code snippet below is self contained and should reproduce the ambiguous function syntax error I saw. Undefining alternative1 makes the error go away, but for no clear reason because the other construct is logically equivalent for these purposes. I'm still working on reproducing the other strange compiler behavior I observed in a standalone test. Note that changing the get_first_name metafunction to directly specify steven and luke as the return types of the operators also makes the error go away, which is not clearly explainable or expected.

#include <vector>
struct true_type { static const bool value = true; };
struct false_type { static const bool value = false; };

#define alternative1
#ifdef alternative1

template <typename T, typename T2>
struct enable_if_T {typedef T2 type; };
template <typename T2>
struct enable_if_T<false_type, T2> {};

#else

template <typename T, typename T2>
struct enable_if_T {};
template <typename T2>
struct enable_if_T<true_type, T2> { typedef T2 type; };

#endif

template <typename T, typename T2>
struct and_2 {};
template <>
struct and_2<true_type, true_type> { typedef true_type type; };

struct luke {};
struct steven {};
struct simonson { typedef luke type; };
struct watanabe { typedef steven type; };

template <typename T> struct is_simonson { typedef false_type type; };
template <> struct is_simonson<simonson> { typedef true_type type; };
template <typename T> struct is_watanabe { typedef false_type type; };
template <> struct is_watanabe<watanabe> { typedef true_type type; };
template <typename T> struct get_first_name { typedef typename T::type type; };

template <typename T, typename T2>
typename enable_if_T<
        typename and_2<
                typename is_watanabe<T>::type,
                typename is_watanabe<T2>::type
>::type,
        typename get_first_name<T>::type
>::type
operator-(const T& lval, const T2& rval) {
        std::cout << "hello steven\n";
        return steven();
}
        
template <typename T, typename T2>
typename enable_if_T<
        typename and_2<
                typename is_simonson<T>::type,
                typename is_simonson<T2>::type
>::type,
        typename get_first_name<T>::type
>::type
operator-(const T& lval, const T2& rval) {
        std::cout << "hello luke\n";
        return luke();
}

#include <iostream>

int main()
{
        simonson s1, s2;
        watanabe w1, w2;
        std::vector<int> v(10);
        std::cout << v.size() << std::endl;
        s1 - s2;
        w1 - w2;
        return 0;
}

1>c:\documents and settings\ljsimons\my documents\visual studio 2008\projects\msvc_bug2\msvc_bug2\msvc_bug2.cpp(76) : error C2593: 'operator -' is ambiguous
1> c:\documents and settings\ljsimons\my documents\visual studio 2008\projects\msvc_bug2\msvc_bug2\msvc_bug2.cpp(63): could be 'luke operator -<simonson,simonson>(const T &,const T2 &)'
1> with
1> [
1> T=simonson,
1> T2=simonson
1> ]
1> c:\documents and settings\ljsimons\my documents\visual studio 2008\projects\msvc_bug2\msvc_bug2\msvc_bug2.cpp(50): or 'T2 operator -<simonson,simonson>(const T &,const T2 &)'
1> with
1> [
1> T=simonson,
1> T2=simonson
1> ]
1> while trying to match the argument list '(simonson, simonson)'
1>c:\documents and settings\ljsimons\my documents\visual studio 2008\projects\msvc_bug2\msvc_bug2\msvc_bug2.cpp(77) : error C2593: 'operator -' is ambiguous
1> c:\documents and settings\ljsimons\my documents\visual studio 2008\projects\msvc_bug2\msvc_bug2\msvc_bug2.cpp(63): could be 'T2 operator -<watanabe,watanabe>(const T &,const T2 &)'
1> with
1> [
1> T=watanabe,
1> T2=watanabe
1> ]
1> c:\documents and settings\ljsimons\my documents\visual studio 2008\projects\msvc_bug2\msvc_bug2\msvc_bug2.cpp(50): or 'steven operator -<watanabe,watanabe>(const T &,const T2 &)'
1> with
1> [
1> T=watanabe,
1> T2=watanabe
1> ]
1> while trying to match the argument list '(watanabe, watanabe)'

Regards,
Luke


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk