Bug 49225 - [C++0x] Weird SFINAE behavior with variadic templates
Summary: [C++0x] Weird SFINAE behavior with variadic templates
Status: RESOLVED DUPLICATE of bug 48322
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.7.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-05-29 19:15 UTC by Paolo Carlini
Modified: 2011-06-15 19:20 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Paolo Carlini 2011-05-29 19:15:49 UTC
I cannot understand why the below compiles, that is why the constructor isn't disabled (whereas a static_assert in the body with the same expression would fire if uncommented). Thanks in advance for any clarification!

//////////////////

template<typename _Tp, _Tp __v>
  struct integral_constant
  {
    static constexpr _Tp                  value = __v;
    typedef _Tp                           value_type;
    typedef integral_constant<_Tp, __v>   type;
    constexpr operator value_type() { return value; }
  };
  
typedef integral_constant<bool, true>     true_type;

typedef integral_constant<bool, false>    false_type;

template<typename _Tp, _Tp __v>
  constexpr _Tp integral_constant<_Tp, __v>::value;

template<bool, typename _Tp = void>
  struct enable_if 
  { };

template<typename _Tp>
  struct enable_if<true, _Tp>
  { typedef _Tp type; };

template<typename, typename>
  struct is_same
  : public false_type { };

template<typename _Tp>
  struct is_same<_Tp, _Tp>
  : public true_type { };

// Just bits of <type_traits> so far...

template<typename...>
  struct __my_and_;

template<typename _B1>
  struct __my_and_<_B1>
  : public _B1
  { };

template<typename... _Args1>
  struct Tt
  {
    template<typename... _Args2, typename = typename
	     enable_if<__my_and_<is_same<_Args1, _Args2>...>::value>::type>
      Tt(_Args2...)
      {
	//static_assert(__my_and_<is_same<_Args1, _Args2>...>::value, "Error");
      }
  };

struct A { };

A a;

Tt<int> t(a); // The static_assert would trigger
Comment 1 Daniel Krügler 2011-05-30 08:46:33 UTC
I did some further investigation of this. The problem seems *not* to be located in __my_and_, but it seems that the compiler expands

is_same<T, U>...

for different T, U to the specialization is_same<T, T> in this scenario - which is obviously incorrect. This could be concluded after either removing the is_same<T, T> definition or by changing its value to false. When removing the definition, the occurring error message reveals, that the instantiation of is_same<A, A> instead of is_same<int, A> is tried, thus pointing to an incorrect expansion that does ignore the _Args1 expansion.
Comment 2 Paolo Carlini 2011-05-30 09:20:30 UTC
Thanks Daniel. Depending on how this issue is resolved - at this point I'm pretty sure it's an actual issue - given also the inconsistency vs the static_assert, I will actually use something similar in the library.
Comment 3 Jason Merrill 2011-06-15 18:01:56 UTC
Yeah, this is a tricky one.

*** This bug has been marked as a duplicate of bug 48322 ***
Comment 4 Paolo Carlini 2011-06-15 19:20:34 UTC
I see. Thus for the time being I'm probably going to use something like the workaround suggested by Daniel in private email.