using sfinae to detect if base classes of a variadic template have specific method

Viewed 267

I am trying to "iterate" over all base classes of a variadic derived class and call a method, named "stream" if it exists.

To check if a method exists I use sfinae, and it works (see commented out code). But when I combine it with variadic template "iteration" if doesn't work, thou the error kinda looks like the sfinae part suddenly works not as expected, when inside the variadic magic.

Help appreciated. I use gcc 5.3.0.

#include <type_traits>
#include <iostream>

namespace detail{
  template<class> struct sfinae_true : std::true_type{};

  template<class T, class A0, class A1> static auto test_stream( int) -> sfinae_true<decltype(
          std::declval<T>().stream(std::declval<A0>(), std::declval<A1>()))>;
  template<class, class A0, class A1> static auto test_stream(long) -> std::false_type;
}

template<class T, class A0, class A1> struct has_stream : decltype(detail::test_stream<T, A0, A1>(0)){};

struct X{ void stream(int, bool){} };
struct A{ void stream(int, bool){} };
struct Y{};

template <typename ... T> class Z : public T ... {
    public:
    void ff() {
        std::initializer_list<bool> {
            ( has_stream<T,int,bool>() ? (T::stream(0, 0) , true) : false) ...
        };
    }
};

int main(){

    Z<X,A> a;
    Z<X,A,Y> b;

/* this works as expected.
    // this runs
    if (has_stream<X, int, bool>()) {
        std::cout << "has int, bool" << std::endl;
    }
    // and this doesn't
    if (has_stream<Y, int, long>()) {
        std::cout << "has int long" << std::endl;
    }
*/

    a.ff(); // no error
    b.ff(); // error

}


$ g++ --std=c++14 -O0 2.cpp                                                                                                                                                     
2.cpp: In instantiation of ‘void Z<T>::ff() [with T = X, A, Y]’:
2.cpp:41:10:   required from here
2.cpp:22:52: error: ‘stream’ is not a member of ‘Y’
             ( has_stream<T,int,bool>() ? (T::stream(0, 0) , true) : false) ...
                                                    ^
2.cpp:21:9: error: no matching function for call to ‘std::initializer_list<bool>::initializer_list(<brace-enclosed initializer list>)’
         std::initializer_list<bool> {
         ^
3 Answers
Related