I have distilled the issue down to the following class which is attempting to use std::enable_if
to disable a member function:
#include <type_traits>
int foo(int& x) {
return x;
}
template<bool enable>
struct A {
int x;
template<bool dummy=true,
typename Enabler = typename std::enable_if<dummy && enable>::type>
auto disabled_method() const -> decltype(foo(x)) {
return foo(x);
}
};
int main() {
A<false> x;
}
There is a type error in the expression decltype(foo(x))
, even though the function should be disabled by the enable_if
!
Note that it is particular to occuring in the return type of the function. For example, if we move the decltype(foo(x))
to the body of the function, SFINAE will work fine:
template<bool dummy=true,
typename Enabler = typename std::enable_if<dummy && enable>::type>
auto disabled_method() const -> int {
decltype(foo((X)x)) local;
return foo(x);
}
(Same for using decltype(foo((X)x))
as an argument type)
Likewise, it will correctly perform SFINAE if I declare it as
template<bool dummy=true,
typename X = const int,
typename Enabler = typename std::enable_if<dummy && enable>::type>
auto disabled_method() const -> decltype(foo((X)x)) {
return foo(x);
}
But using decltype(foo((const int)x))
, it will error out, despite X being equal to const int
above. This seems to indicate that introducing the extra cast to the template parameter X
causes it to delay the substitution.
But the dummy
and Enabler
template pattern up above is supposed to do that anyways?
Why is this happening?