Confusion with hard error in SFINAE

Viewed 485

With regards to the following code (https://wandbox.org/permlink/nhx4pheijpTF1ohf reproduced below for convenience)

#include <type_traits>
#include <utility>

namespace foo_name {
template <typename T>
void foo();
template <>
void foo<int>();

template <typename T>
struct c_size;
template <>
struct c_size<int> : public std::integral_constant<int, 1> {};
} // namespace foo_name

template <typename Type>
class Foo {
public:
    template <typename T>
    static decltype(auto) impl(T&& t) {
        using foo_name::foo;
        return foo(std::forward<T>(t));
    }
};

class Something {};

template <typename Type, typename T = std::decay_t<Type>>
using EnableIfHasFoo = std::void_t<
    decltype(Foo<T>::impl(std::declval<T>())),
    decltype(foo_name::c_size<Type>::value)>;

template <typename Type, typename = std::void_t<>>
class Test {};
template <typename Type>
class Test<Type, EnableIfHasFoo<Type>> {};

int main() {
    static_cast<void>(Test<Something>{});
}

The code above exits with an error because the instantiation of Foo<T>::impl() causes a hard error and is not usable in a SFINAE context. But the strange thing here is that when you switch the order of things in the void_t in EnableIfHasFoo (to the following https://wandbox.org/permlink/at1KkeCraNwHGmUI), it will compile

template <typename Type, typename T = std::decay_t<Type>>
using EnableIfHasFoo = std::void_t<
    decltype(foo_name::c_size<Type>::value),
    decltype(Foo<T>::impl(std::declval<T>()))>;

Now the questions are

  1. Why does the code initially not compile? The instantiation of Foo<T>::impl() is in context of the substitution, so it should work?
  2. Substituting foo_name::foo(T) in place of the first argument to void_t will make it compile (see https://wandbox.org/permlink/g3NaPFZxdUPBS7oj), why? How does adding one extra layer of indirection make the situation different?
  3. Why does the order in void_t make a difference, does the compiler short circuit the expressions within the type pack?
1 Answers
Related