Below SFINAE code with variadic templates compiles nicely using clang 3.7.1, C++14:
#include <array>
#include <iostream>
#include <vector>
#include <cstdint>
enum class Bar : uint8_t {
ay, bee, see
};
struct S {
static void foo() {}
// std::begin(h) is defined for h of type H
template<typename H, typename... T>
static typename std::enable_if<std::is_pointer<decltype(std::begin(std::declval<H>()))*>::value>::type
foo(const H&, T&&... t)
{ std::cout << "container\n"; foo(std::forward<T>(t)...); }
// H is integral
template<typename H, typename... T>
static typename std::enable_if<std::is_integral<typename std::remove_reference<H>::type>::value>::type
foo(const H&, T&&... t)
{ std::cout << "integer\n"; foo(std::forward<T>(t)...); }
// H is an enum with underlying type = uint8_t
/*
template<typename H, typename... T>
static typename std::enable_if<std::is_same<typename std::underlying_type<H>::type,uint8_t>::value>::type
foo(const H&, T&&... t)
{ std::cout << "enum\n"; foo(std::forward<T>(t)...); }
*/
};
int main()
{
S::foo(std::array<int,8>(), 5, 5L, std::vector<int>{}, 5L);
}
I want the correct overload of foo
to be called recursively, based on the type H
:
- if
std::begin(h)
is defined for anh
of typeH
, I want the overload number 1 to be chosen - if
H
is an "integral type", I want overload number 2.
This works as it is. But if I add another overload for enum types (you can try to un-comment the third overload), then I get:
error: only enumeration types have underlying types
I agree that only enums got an underlying type, hence why is Not the third overload (with std::underlying_type
) get SFINAE-d away?
std::enable_if<std::is_enum<H>::value>::type
? It compiles fine. Are you specific forenum
s with underlying types ofuint8_t
only? In that case, you can add 1 more condition ofsizeof(H) == sizeof(uint8_t)
. i.e..std::is_enum<H>::value && (sizeof(H) == sizeof(uint8_t))
. That's covered in the ideone example above. – Llanes