I'm working on a little compile time helper that let's me determine if a function (for now: no namespaces or class member functions) with a specific signature exists (e.g. __builtin_pop_count which is widely spread, but not guaranteed to be available on any platform).
For a fixed number of arguments, this is easily done:
template <typename ReturnType, typename ArgumentType, typename = void>
struct Exists : std::false_type // Base case
{
};
template <typename T>
using void_t = void;
template <typename T>
using return_t = decltype(foo(std::declval<T>())); // here it is hidden: foo, although this symbol is never declared!
// specialization (compiler has to pick this one if no substitution failure in return_t
template <typename ReturnType, typename ArgumentType>
struct Exists<ReturnType, ArgumentType, void_t<return_t<ArgumentType>>>
: std::is_same<return_t<ArgumentType>, ReturnType> // check the return type
{
};
static_assert(!Exists<void, int>::value, "");
static_assert(!Exists<void, void>::value, "");
static_assert(!Exists<void, char*>::value, "");
static_assert(!Exists<int, void>::value, "");
static_assert(!Exists<int, int>::value, "");
static_assert(!Exists<int, char*>::value, "");
This compiles fine. Adding the function void foo(int) negates the first assertion, but leaves the rest intact.
Now I would like to extend this helper to support an arbitrary number of argument types.
However,
template <typename ReturnType, typename... ArgumentTypes, typename = void>
cannot work, because typename... must be at the end of the list,
template <typename ReturnType, typename = void, typename... ArgumentTypes>
on the other hand requires the following ArgumentTypes to have a default type which also is not possible.
How can I circumvent this? Can a std::tuple<ArgumentTypes...> help in any way?