Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does using ellipses for SFINAE work?

When using SFINAE to select constructor overloads in the past, I have typically used the following:

template <typename T>
class Class {
public:
    template <typename U = T, typename std::enable_if<std::is_void<U>::value, int>::type=0>
    Class() {
        std::cout << "void" << std::endl;
    }

    template <typename U = T, typename std::enable_if<!std::is_void<U>::value, int>::type=0>
    Class() {
        std::cout << "not void" << std::endl;
    }
};

However, I just came across this alternative:

template <typename U = T, typename std::enable_if<std::is_void<U>::value>::type...>
Class() {
    std::cout << "void" << std::endl;
}

Considering that the following is illegal ...

template <typename U = T, void...> // ERROR!
Class() { }

... how does the alternative above using ellipses rather than a non-type template argument work?


Full code: http://coliru.stacked-crooked.com/a/64a1aaf13ce6099b

like image 616
zennehoy Avatar asked Aug 08 '16 16:08

zennehoy


Video Answer


1 Answers

My previous answer was wrong. Sorry. I'm just going to fix it.


This declaration:

template <typename U = T, void...>
Class() { }

violates [temp.res]/8:

The program is ill-formed, no diagnostic required, if [...] every valid specialization of a variadic template requires an empty template parameter pack

It's no diagnostic required, but the compiler chooses to issue one anyway. Either way, the code is ill-formed.

On the other hand

template <typename U = T, std::enable_if_t<std::is_void<U>::value>...>
Class() { }

doesn't violate this requirement. We have an empty pack, so we don't run afoul of the fact that you can't use void as a non-type template parameter. Additionally, a hypothetical specialization of enable_if could provide a type that isn't void there so it's not ill-formed due to the above limitation.

like image 71
Barry Avatar answered Oct 02 '22 11:10

Barry