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...>

?

+3


source to share


1 answer


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.

+5


source







All Articles