9

I'm trying out examples from Walter Brown's TMP talk and I'm trying to get his has_member implementation working.

However the implementation seems to falsely return true which leads me to believe there is some detail of SFINAE that I am not understanding.

#include <iostream>
#include <type_traits>

template <class ...>
using void_t = void;

template <class, class = void>
struct has_type_member: std::false_type {};

template <class T> 
struct has_type_member<T, void_t<typename T::type> >: std::true_type {};

struct FooWithType
{
    typedef int type;
};

struct FooNoType 
{
};

int main()
{
    std::cout << "Does FooWithType have type member? " << 
        (has_type_member<FooWithType>() ? "YES" : "NO") << "\n";

    std::cout << "Does FooNoType have type member? " << 
        (has_type_member<FooNoType>() ? "YES" : "NO") << "\n";

    return 1;                                                                                                                 
}      

Output is:

Does FooWithType have type member? YES
Does FooNoType have type member? YES

I am on gcc 4.8.2 on Ubuntu.

Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
Nathan Doromal
  • 3,437
  • 2
  • 24
  • 25
  • 1
    Are you sure your void_t implementation is fine? That's not how I remember it being implemented. Maybe it returns void even for ill-formed templates? – KABoissonneault Jun 11 '15 at 13:01
  • See [N3909](http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2014/n3909.pdf), [N4436](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4436.pdf) and [CWG 1558](http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1558) – dyp Jun 11 '15 at 13:05
  • Related/duplicate: [C++11: SFINAE in template parameters, GCC vs Clang](http://stackoverflow.com/q/28282398/) – dyp Jun 11 '15 at 13:07
  • Further duplicates: http://stackoverflow.com/q/25833356/ http://stackoverflow.com/q/26687062/ – dyp Jun 11 '15 at 13:10
  • 1
    With g++5, it works as expected. – iammilind Jun 11 '15 at 13:46

1 Answers1

11

The problem is that gcc 4.8.2 (and prior to gcc 5.0) does not regard unused arguments in alias templates as suitable for SFINAE. The workaround is to forward to a voider class template:

template <class ... T> struct voider { using type = void; };
template <class ... T>
using void_t = typename voider<T...>::type;

From http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3911.pdf section 2.3:

Alas, we have encountered implementation divergence (Clang vs. GCC) while working with the above very simple definition. We (continue to) conjecture that this is because of CWG issue 1558: “The treatment of unused arguments in an alias template specialization is not specified by the current wording of 14.5.7 [temp.alias].”

ecatmur
  • 152,476
  • 27
  • 293
  • 366