Get function arity from template parameter - c++

How can I get the arity of an arbitrary function type used as a template parameter?
The function can be a normal function, a lambda or a functor. Example:
template<typename TFunc>
std::size_t getArity()
{
// ...?
}
template<typename TFunc>
void printArity(TFunc mFunc)
{
std::cout << "arity: " << getArity<TFunc>() << std::endl;
}
void testFunc(int) { }
int main()
{
printArity([](){}); // prints 0
printArity([&](int x, float y){}); // prints 2
printArity(testFunc); // prints 1
}
I have access to all C++14 features.
Do I have to create specialization for every function type (and all respective qualifiers)?
Or is there an easier way?

Assuming that all the operator()'s and functions we're talking about are not templates or overloaded:
template <typename T>
struct get_arity : get_arity<decltype(&T::operator())> {};
template <typename R, typename... Args>
struct get_arity<R(*)(Args...)> : std::integral_constant<unsigned, sizeof...(Args)> {};
// Possibly add specialization for variadic functions
// Member functions:
template <typename R, typename C, typename... Args>
struct get_arity<R(C::*)(Args...)> :
std::integral_constant<unsigned, sizeof...(Args)> {};
template <typename R, typename C, typename... Args>
struct get_arity<R(C::*)(Args...) const> :
std::integral_constant<unsigned, sizeof...(Args)> {};
// Add all combinations of variadic/non-variadic, cv-qualifiers and ref-qualifiers
Demo.

Related

Multiple parameter packs in a single function?

I'm trying to create a function that takes two parameter packs of objects. There are two templated base classes and I'd like to pass instances of derived classes to this function. Consider this example.
template <int N>
struct First {};
template <int N>
struct Second {};
// there are a few of these
struct FirstImpl : First<5> {};
struct SecondImpl : Second<7> {};
template <int... firstInts, int... secondInts>
void function(float f, First<firstInts> &... first, Second<secondInts> &... second) {
// ...
}
What I would like to do is call function like this
FirstImpl firstImpl;
OtherFirstImpl otherFirstImpl;
SecondImpl secondImpl;
OtherSecondImpl otherSecondImpl;
function(9.5f, firstImpl, otherFirstImpl, secondImpl, otherSecondImpl);
but this example won't compile. The compiler seems to be trying to pack everything into the second parameter pack and failing because FirstImpl can't be implicitly converted Second<N>.
How do I get around this?
It's pretty much next to impossible to define something with two variadic parameter packs. Once a variadic parameter pack gets encountered, it likes to consume all remaining parameters, leaving no crumbs for the second pack to feed on.
However, as I mentioned, in many cases you can use tuples, and with deduction guides in C++17, the calling convention is only slightly longer than otherwise.
Tested with gcc 7.3.1, in -std=c++17 mode:
#include <tuple>
template <int N>
struct First {};
template <int N>
struct Second {};
template <int... firstInts, int... secondInts>
void function(std::tuple<First<firstInts>...> a,
std::tuple<Second<secondInts>...> b)
{
}
int main(int, char* [])
{
function( std::tuple{ First<4>{}, First<3>{} },
std::tuple{ Second<1>{}, Second<4>{} });
}
That's the basic idea. In your case, you have subclasses to deal with, so a more sophisticated approach would be necessary, probably with an initial declaration of two tuples being just a generic std::tuple< First...> and std::tuple<Second...>, with some additional template-fu. Probably need to have First and Second declare their own type in a class member declaration, and then have the aforementioned template-fu look for the class member, and figure out which superclass it's dealing with.
But the above is the basic idea of how to designate two sets of parameters, from a single variadic parameter list, and then work with it further...
Let's first code a variable template which determines whether a type derives from First or not:
template <int N>
constexpr std::true_type is_first(First<N> const &) { return {}; }
template <int N>
constexpr std::false_type is_first(Second<N> const &) { return {}; }
template <class T>
constexpr bool is_first_v = decltype( is_first(std::declval<T>()) )::value;
And a struct Split which collects the indices of the First and Second types:
template <class, class, class, std::size_t I = 0> struct Split;
template <
std::size_t... FirstInts,
std::size_t... SecondInts,
std::size_t N
>
struct Split<
std::index_sequence<FirstInts...>,
std::index_sequence<SecondInts...>,
std::tuple<>,
N
> {
using firsts = std::index_sequence<FirstInts...>;
using seconds = std::index_sequence<SecondInts...>;
};
template <
std::size_t... FirstInts,
std::size_t... SecondInts,
std::size_t I,
typename T,
typename... Tail
>
struct Split<
std::index_sequence<FirstInts...>,
std::index_sequence<SecondInts...>,
std::tuple<T, Tail...>,
I
> : std::conditional_t<
is_first_v<T>,
Split<std::index_sequence<FirstInts..., I>,
std::index_sequence<SecondInts...>,
std::tuple<Tail...>,
I + 1
>,
Split<std::index_sequence<FirstInts...>,
std::index_sequence<SecondInts..., I>,
std::tuple<Tail...>,
I + 1
>
> {};
And like I told you in the comments, adding a member value to First and Second (or inheriting from std:integral_constant), this allows us to write the following:
template <std::size_t... FirstIdx, std::size_t... SecondIdx, typename Tuple>
void function_impl(float f, std::index_sequence<FirstIdx...>, std::index_sequence<SecondIdx...>, Tuple const & tup) {
((std::cout << "firstInts: ") << ... << std::get<FirstIdx>(tup).value) << '\n';
((std::cout << "secondInts: ") << ... << std::get<SecondIdx>(tup).value) << '\n';
// your implementation
}
template <class... Args>
void function(float f, Args&&... args) {
using split = Split<std::index_sequence<>,std::index_sequence<>, std::tuple<std::decay_t<Args>...>>;
function_impl(f, typename split::firsts{}, typename split::seconds{}, std::forward_as_tuple(args...));
}
Demo
Why won't you simply pass the class itself as template parameter? Like this:
template <int N>
struct First {};
template <int N>
struct Second {};
// there are a few of these
struct FirstImpl : First<5> {};
struct SecondImpl : Second<7> {};
template <typename FirstSpec, typename SecondSpec>
void function(float f, FirstSpec & first, SecondSpec & second) {
// ...
}
Not exactly what you asked but... you could unify the two list using a variadic template-template int container (Cnt, in the following example) and next detect, for every argument, if is a First or a Second (see the use of std::is_same_v)
The following is a full working example
#include <string>
#include <vector>
#include <iostream>
#include <type_traits>
template <int>
struct First {};
template <int>
struct Second {};
// there are a few of these
struct FirstImpl : First<5> {};
struct SecondImpl : Second<7> {};
template <template <int> class ... Cnt, int... Ints>
void function (float f, Cnt<Ints> & ... args)
{
(std::cout << ... << std::is_same_v<Cnt<Ints>, First<Ints>>);
}
int main()
{
FirstImpl firstImpl;
FirstImpl otherFirstImpl;
SecondImpl secondImpl;
SecondImpl otherSecondImpl;
function(9.5f, firstImpl, otherFirstImpl, secondImpl, otherSecondImpl);
}

get number of parameters of any callable object at compile time in C++14 [duplicate]

How can I get the arity of an arbitrary function type used as a template parameter?
The function can be a normal function, a lambda or a functor. Example:
template<typename TFunc>
std::size_t getArity()
{
// ...?
}
template<typename TFunc>
void printArity(TFunc mFunc)
{
std::cout << "arity: " << getArity<TFunc>() << std::endl;
}
void testFunc(int) { }
int main()
{
printArity([](){}); // prints 0
printArity([&](int x, float y){}); // prints 2
printArity(testFunc); // prints 1
}
I have access to all C++14 features.
Do I have to create specialization for every function type (and all respective qualifiers)?
Or is there an easier way?
Assuming that all the operator()'s and functions we're talking about are not templates or overloaded:
template <typename T>
struct get_arity : get_arity<decltype(&T::operator())> {};
template <typename R, typename... Args>
struct get_arity<R(*)(Args...)> : std::integral_constant<unsigned, sizeof...(Args)> {};
// Possibly add specialization for variadic functions
// Member functions:
template <typename R, typename C, typename... Args>
struct get_arity<R(C::*)(Args...)> :
std::integral_constant<unsigned, sizeof...(Args)> {};
template <typename R, typename C, typename... Args>
struct get_arity<R(C::*)(Args...) const> :
std::integral_constant<unsigned, sizeof...(Args)> {};
// Add all combinations of variadic/non-variadic, cv-qualifiers and ref-qualifiers
Demo.

C++ deduce member function parameters

I'm looking to extend the functionality described here but for member functions, what would be the syntax in this case?
Also, the (*) in the template definition, is that de-referencing the function pointer so the compiler can deduce the template arguments?
Would appreciate any input!
Thanks
template <class F> struct ArgType;
template <class R, class T>
struct ArgType<R(*)(T)> {
typedef T type;
};
void f(int) {}
#include <type_traits>
#include <iostream>
int main() {
// To prove
std::cout << std::is_same< ArgType<decltype(&f)>::type, int >::value << '\n';
// To use
ArgType<decltype(&f)>::type a;
}
Pointer-to-members look like Ret (Cls::*)(Args...) [cv-qualifiers] [ref-qualifiers]. So you can extend your class to deduce the first type thusly:
template <class F> struct ArgType;
template <typename Ret, typename Cls, typename T, typename... Args>
struct ArgType<Ret (Cls::*)(T, Args...)> {
using type = T;
};
Note that you can make this more generic by write a metafunction that gives you the nth argument:
template <typename Ret, typename Cls, typename... Args>
struct ArgType<Ret (Cls::*)(Args...)> {
template <size_t N>
struct get_arg {
using type = typename std::tuple_element<N,
std::tuple<Args...>>::type;
};
};
So ArgType<F>::arg<0>::type would be the type you seek.

Partial template specialization for variadic template where [Args...] is empty

I have a class, Delegate, declared like this:
template<typename T> class Delegate;
template<typename R, typename... Args>
class Delegate<R(Args...)>
{ /*...*/ };
It can be instantiated for a function returning a ReturnType and taking no arguments as a Delegate<ReturnType()>. I've run into an issue that requires me to specialize the class' () operator for this case, but haven't been able to figure out how to coerce the compiler doing so without a compiler error.
I have the following function:
template <typename R, typename... Args>
R Delegate<R(Args...)>::operator()(Args... args)
{ /*...*/ }
Adding the following specialization, I get an an error saying invalid use of incomplete type 'class Delegate<R()>':
template <typename R>
R Delegate<R()>::operator()()
{ /*...*/ }
but I can't simply replace Args... with void either, as far as I've been able to tell... What is the proper procedure here, and (if this question applies and you are feeling extra helpful) why?
Your attempt with using R Delegate<R()>::operator()() to specialize even more the member function of a partial specialization of a class template fails due to §14.5.5.3 [temp.class.spec.mfunc]:
1 The template parameter list of a member of a class template partial specialization shall match the template parameter list of the class template partial specialization.
In other words:
template <typename R>
R Delegate<R()>::operator()() { /**/ }
is actually a specialization of operator() of your primary template:
template <typename T>
class Delegate;
and since it's an incomplete type, you end up with the error. The possible workarounds are:
Option #1
Specialize the entire class and reimplement all the members of that class:
template <typename T>
class Delegate;
template <typename R, typename... Args> // partial specialization for non-empty Args
class Delegate<R(Args...)>
{
R operator()(Args...) { return {}; }
};
template <typename R> // partial specialization for empty Args
class Delegate<R()>
{
R operator()() { return {}; }
};
DEMO 1
Option #2
Use a one more delegate class that is specialized:
#include <utility>
template <typename T>
struct Impl;
template <typename R, typename... Args>
struct Impl<R(Args...)>
{
static R call(Args&&...) { return {}; }
};
template <typename R>
struct Impl<R()>
{
static R call() { return {}; }
};
template <typename T>
class Delegate;
template <typename R, typename... Args>
class Delegate<R(Args...)>
{
R operator()(Args... args)
{
return Impl<R(Args...)>::call(std::forward<Args>(args)...);
}
};
DEMO 2
Option #3
Use some ugly SFINAE:
#include <type_traits>
template <typename T>
class Delegate;
template <typename R, typename... Args>
class Delegate<R(Args...)>
{
template <typename T = R>
typename std::enable_if<sizeof...(Args) != 0 && std::is_same<T,R>{}, R>::type
operator()(Args...) { return {}; }
template <typename T = R>
typename std::enable_if<sizeof...(Args) == 0 && std::is_same<T,R>{}, R>::type
operator()() { return {}; }
};
DEMO 3
Option #4
Inherit from a specialized class template, possibly utilizing the CRTP idiom:
template <typename T>
class Delegate;
template <typename T>
struct Base;
template <typename R, typename... Args>
struct Base<Delegate<R(Args...)>>
{
R operator()(Args...)
{
Delegate<R(Args...)>* that = static_cast<Delegate<R(Args...)>*>(this);
return {};
}
};
template <typename R>
struct Base<Delegate<R()>>
{
R operator()()
{
Delegate<R()>* that = static_cast<Delegate<R()>*>(this);
return {};
}
};
template <typename R, typename... Args>
class Delegate<R(Args...)> : public Base<Delegate<R(Args...)>>
{
friend struct Base<Delegate<R(Args...)>>;
};
DEMO 4

Creating POD with variable number of elems

I would like to have a type, that would be in effect POD but I would like to be able to specify how and which types are in it, for example:
template<Args...>
struct POD
{
//here I would like to create depending on Args appropriate types as a members.
};
Is it possible to do it with this new variadic templates feature in C++0x?
I’ve never yet used the C++0x variadic templates feature but the following code compiles on G++ 4.5:
template <typename... Args>
struct tuple;
template <typename T, typename... Args>
struct tuple<T, Args...> {
T value;
tuple<Args...> inner;
};
template <typename T>
struct tuple<T> {
T value;
};
However, initializing them is … weird because we need to nest the inner values:
int main() {
tuple<int> n1 = { 23 };
tuple<int, float> n2 = { 42, { 0.5f } };
tuple<std::string, double, int> n3 = { "hello, world", { 3.14, { 97 } } };
}
Retrieving the values is of course a bit tedious. The simplest method is probably to provide a get<N>() function template.
But we cannot implement get directly since function templates cannot be partially specialized. Either we need to use SFINAE (read: boost::enable_if) or we need to delegate the actual function of get to a type that can be partially specialized.
In the following, I did the latter. But first, we need another helper type trait: nth_type, which returns the appropriate return type of the get function:
template <unsigned N, typename... Args>
struct nth_type;
template <unsigned N, typename T, typename... Args>
struct nth_type<N, T, Args...> : nth_type<N - 1, Args...> { };
template <typename T, typename... Args>
struct nth_type<0, T, Args...> {
typedef T type;
};
Easy-peasy. Just returns the nth type in a list of types.
Now we can write our get function:
template <unsigned N, typename... Args>
inline typename nth_type<N, Args...>::type get(tuple<Args...>& tup) {
return get_t<N, Args...>::value(tup);
}
Like I said, this just delegates the task. No biggie. In practice, we probably want to have another overload for const tuples (but then, in practice we would use an existing tuple type).
Now for the killing, followed by a light salad:
template <unsigned N, typename... Args>
struct get_t;
template <unsigned N, typename T, typename... Args>
struct get_t<N, T, Args...> {
static typename nth_type<N, T, Args...>::type value(tuple<T, Args...>& tup) {
return get_t<N - 1, Args...>::value(tup.inner);
}
};
template <typename T, typename... Args>
struct get_t<0, T, Args...> {
static T value(tuple<T, Args...>& tup) {
return tup.value;
}
};
And that’s it. We can test this by printing some values in our previously defined variables:
std::cout << get<0>(n1) << std::endl; // 23
std::cout << get<0>(n2) << std::endl; // 42
std::cout << get<0>(n3) << std::endl; // hello, world
std::cout << get<1>(n2) << std::endl; // 0.5
std::cout << get<1>(n3) << std::endl; // 3.14
std::cout << get<2>(n3) << std::endl; // 97
Man, it’s fun messing with variadic templates.
Are you familiar with std::tuple?
AFAIK it's a POD if all it's members are PODs, if I'm wrong then I'm guessing it isn't possible.