Determining the Runtime of Compilation Functions
I am working on a little compile-time helper that allows me to determine if a function (at the moment: no namespaces or class member functions) exists with a specific signature (for example __builtin_pop_count
, which is widely distributed but is not guaranteed to be available on any platform) ...
For a fixed number of arguments, this is easy to do:
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. The addition of the function void foo(int)
negates the first statement, but leaves it 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 it typename...
must be at the end of the list,
template <typename ReturnType, typename = void, typename... ArgumentTypes>
On the other hand, requires the following argument types to have a default type, which is also not possible.
How can I get around this? Can anyone help std::tuple<ArgumentTypes...>
?
source to share
You guessed it. Use a template pack
and simplify a little:
template <typename...> struct pack {}; // To be potentially introduced in C++1Z
template <typename, typename, typename=void>
struct Exists_impl : std::false_type {};
template <typename R, typename... Args>
struct Exists_impl<R, pack<Args...>,
std::enable_if_t<std::is_same<decltype(foo(std::declval<Args>()...)), R>::value>>
: std::true_type {};
template <typename R, typename... Args>
using Exists = Exists_impl<R, pack<Args...>>;
Demo .
Note that this template will never be able to find features likevoid(int)
through ADL, as in this case the set of associated namespaces is empty. These functions must be declared at the point of definition.
It might also be appropriate to useis_convertible
insteadis_same
to check the return type depending on the use case.
source to share