How can I find the number of arguments a template function takes? - c++

I have the following type trait:
template <class T>
struct Arity : Arity<decltype(&T::operator())> {};
template <class T, class R, class... Args>
struct Arity<R(T::*)(Args...)> {
static constexpr auto value = sizeof...(Args);
};
template <class T, class R, class... Args>
struct Arity<R(T::*)(Args...) const> {
static constexpr auto value = sizeof...(Args);
};
template <class R, class... Args>
struct Arity<R(*)(Args...)> {
static constexpr auto value = sizeof...(Args);
};
Which works great to find the number of arguments a function takes for most use cases, but it fails for one common case:
auto l1 = [](int, double){};
Arity<decltype(l1)>::value; // works, 2
auto l2 = [](auto, auto){};
Arity<decltype(l2)>::value; // error: Reference to overloaded function could not be resolved; did you mean to call it?
I believe it's impossible to generally make this work for any templated function / operator() because depending on the types/values passed as template types, a different overload could be selected, or perhaps no overload may be available at all. Also, there's no way to know what valid types and values to pass as template arguments. But still, I want this to work for the common case of a lambda taking auto arguments. Is there any way to make this more robust and cover lambdas which take auto arguments?

I guess I achieved half of a solution here. Only works up to a fixed number of parameters, but for most applications that shouldn't be an issue. Also, it's probably highly simplifiable but my brain is not into tricky SFINAE right now.
template <
class, std::size_t N,
class = std::make_index_sequence<N>,
class = void_t<>
>
struct CanCall : std::false_type { };
template <class F, std::size_t N, std::size_t... Idx>
struct CanCall<
F, N,
std::index_sequence<Idx...>,
void_t<decltype(std::declval<F>()((Idx, std::declval<Any const&&>())...))>
> : std::true_type { };
CanCall<F, N> will return whether F is callable with N parameters of arbitrary type. The Any helper type has templated implicit conversion operators that allows it to morph into any desired parameter type.
template <class F, std::size_t N = 0u, class = void>
struct Arity : Arity<F, N + 1u, void> { };
template <class F, std::size_t N>
struct Arity<F, N, std::enable_if_t<CanCall<F, N>::value>>
: std::integral_constant<std::size_t, N> { };
template <class F>
struct Arity<F, MAX_ARITY_PROBING, void>
: std::integral_constant<std::size_t, ARITY_VARIADIC> { };
Arity<F> just checks whether an F can be called with zero, one, two... parameters. First positive check wins. If we reach MAX_ARITY_PROBING parameters, Arity bails out and supposes that the function is either variadic, or is not a function at all.
See it live on Coliru

I don't think you can use lambda functions in your use case whose argument types are auto. The operator() functions of such lambda functions are most likely implemented using function templates.
Hence, decltype can't be used with:
auto l2 = [](auto, auto){};
Arity<decltype(l2)>::value;
See this answer to another SO question for more on the subject.

Related

How can I determine the return type of a functor which takes that type for a parameter?

Suppose I have to following function:
template <typename Op, typename T> T foo(Op op) { }
Op is assumed to have the following method:
T Op::operator()(T&);
(this is a simple case; actually it might have more parameters but their types are known to me).
Now, I want to set a default for the T parameter. The problem is, in order to faux-invoke it (e.g. as in std::result_of<Op::operator()(int&)> I need to have the type of the parameter - which is exactly the type I'm missing.
Is it possible to determine T from Op? So that I may, for example, call:
foo( [](int& x){ return x++; } );
I'm interested in a C++11 solution; if you need a later-standard-version capability, that's also interesting (especially the explanation of why that is).
Note: If Op has multiple compatible operator()'s taking references to different types, I'm ok with having to specifyT` myself, of course - but the compilation should pass when I do that.
If the function object has exactly one signature, you can discover that signature by decltype(&T::operator()) and infer from that:
template<class T> struct X : X<decltype(&T::operator())> {}; // #1
template<class T> struct X<T(T&) const> { using type = T; }; // #2
template<class C, class M> struct X<M (C::*)> : X<M> {}; // #3
// add more specializations for mutable lambdas etc. - see example
template <typename Op, typename T = typename X<Op>::type>
T foo(Op op) { /* ... */ }
Example (C++11).
This is a series of type transformations, expressed as partial template specializations. From a lambda with anonymous type <lambda>, we extract its function call operator type at #1 giving a member function pointer type such as int (<lambda>::*)(int&) const, which matches #3 allowing us to discard the class type giving an abominable function type int(int&) const, which matches #2 allowing us to extract the argument and return type, exposed as X::type which is visible to the original instantiation of X via inheritance. Using partial specializations of the same template for different type computations is a code-golf trick and you might want to avoid it (and use more expressive names) in production code.
If on the other hand the function object has more than one signature (template parameters, default parameters, overloaded, hand-crafted function objects, etc.) then this will not work; you will need to wait for stronger forms of reflection to enter the language.
The existence of template functions shows the question is impossible to answer in general:
struct post_increment
{
template<typename T>
T operator()(T& t) const
{
return t++;
}
};
foo(post_increment{});
// or in C++14: foo([](auto& t) { return t++; });
The result of a function foo taking a mapping T& to T for some set of types T is itself polymorphic. In some cases, this is expressible even in C++11:
template<typename Op>
struct foo_result_t
{
template<typename T>
operator T() const
{
T t {};
op(t);
return t;
}
Op op;
};
template <typename Op>
foo_result_t<Op> foo(Op op)
{
return {op};
}
int i = foo(post_increment{}); // use it with an int
Another solution in case of exactly one signature.
Another... well... almost the same ecatmur's solution but based on a template function, to deduce the types, instead of a template class.
All you need is a declared function two declared functions that deduce the types (and return the same return type of the operator(); you can develop also another function to return, by example, std::tuple<Args...>, if you needs to extract the Args... types)
template <typename T, typename R, typename ... Args>
R deducer (R(T::*)(Args...) const);
template <typename T, typename R, typename ... Args>
R deducer (R(T::*)(Args...));
and a using (a little decltype() delirium) to extract the R type
template <typename T>
using RetType = decltype(deducer(std::declval<decltype(&T::operator())>()));
The following is a full C++11 example
#include <utility>
struct A
{
long operator() (int, char, short)
{ return 0l; }
};
template <typename T, typename R, typename ... Args>
R deducer (R(T::*)(Args...) const);
template <typename T, typename R, typename ... Args>
R deducer (R(T::*)(Args...));
template <typename T>
using RetType = decltype(deducer(std::declval<decltype(&T::operator())>()));
int main ()
{
auto f = [](int& x) { return x++; };
static_assert( std::is_same<RetType<A>, long>::value, "!" );
static_assert( std::is_same<RetType<decltype(f)>, int>::value, "!" );
}
If you wont to manage also volatile operators, you have to add other two deducer()
template <typename T, typename R, typename ... Args>
R deducer (R(T::*)(Args...) volatile const);
template <typename T, typename R, typename ... Args>
R deducer (R(T::*)(Args...) volatile);

Q: Template class that takes either a normal type or a template template argument

Recently I designed meta-types and the possible operations that would allow compile-time type concatenations:
#include <tuple>
template<template<typename...> typename T>
struct MetaTypeTag
{};
/*variable template helper*/
template<template<typename...> typename T>
constexpr MetaTypeTag<T> meta_type_tag = {};
template<typename T>
struct TypeTag
{};
/*comparison*/
template<typename T>
constexpr bool operator==(TypeTag<T>, TypeTag<T>) { return true; }
template<typename T, typename U>
constexpr bool operator==(TypeTag<T>, TypeTag<U>) { return false; }
/*variable template helper*/
template<typename T>
constexpr TypeTag<T> type_tag = {};
template<template<typename...> typename T, typename... Ts>
constexpr TypeTag<T<Ts...>> combine(MetaTypeTag<T>, TypeTag<Ts>...)
{
return {};
}
int main()
{
constexpr auto combined_tag = combine(meta_type_tag<std::tuple>, type_tag<int>, type_tag<float>);
static_assert(combined_tag == type_tag<std::tuple<int, float>>, "");
}
The std::tuple without template arguments cannot be used as a type, but may still appear in the template template parameter.
Now if we try to go one step further, the question is whether there is any way to unify struct MetaTypeTag and struct TypeTag, since they are both empty classes with one template parameter, or at least it could be possible to use the same variable template type_tag but redirect to a different class depending on the type category? So I would imagine something like this:
template<???>
constexpr auto type_tag = ????{};
//use with 'incomplete type'
type_tag<std::tuple> //MetaTypeTag<std::tuple>
//use with regular type
type_tag<int> //TypeTag<int>
I tried all possible ways - redefinition, explicit specialization, partial specialization, optional template parameters, conditional using alias, but none worked. I had hoped C++17's template<auto> would help, but it turns out that one is for non-type only.
the question is whether there is any way to unify struct MetaTypeTag and struct TypeTag, since they are both empty classes with one template parameter
I don't thinks so.
The best I can imagine to simplify a little (very a little) your code is define a couple of overloaded constexpr function, say getTag()
template <typename T>
auto constexpr getTag ()
{ return TypeTag<T>{}; }
template <template <typename ...> typename T>
auto constexpr getTag ()
{ return MetaTypeTag<T>{}; }
so you can call getTag<T>() where T is either a type or a template.
So you can call combine() as follows
constexpr auto combined_tag
= combine(getTag<std::tuple>(), getTag<int>(), getTag<float>());
But I don't think is a great improvement.

Autogenerate function header, variadic template

I have a problem, I defined a template class to cope with systems of different dimensions as a follow:
template <std::size_t N>
class system {
std::array<cv::Mat, N> matrices;
...
};
then I need to define different function that takes different parameters based on the size of the system. Something like that:
template <>
template<typename T>
void system<1>::fun(T & a){ }
template <>
template<typename T>
void system<2>::fun(T & a, T & b){ }
template <>
template<typename T>
void system<3>::fun(T & a, T & b, T & c){ }
However tried to uses this strategy the compiler gives the following error:
Out-of-line definition of 'fun' does not match any declaration in 'system<3>'
Moreover I would like that the headers functions will be autogenerate based on the template parameter N. I tried to use variadic template but without fortune.
I believe you could also make foo more generic using integer_sequence and alias template. (integer_sequence is c++14 but there exist c++11 implementations as well):
#include <utility>
#include <array>
template <class T, std::size_t>
using typer = T;
template <std::size_t N, class = std::make_index_sequence<N>>
struct S;
template <std::size_t N, std::size_t... Is>
struct S<N, std::index_sequence<Is...>>{
std::array<int, N> matrices;
template <class T>
void foo(typer<const T&, Is>... args) {
int dummy[] = { ((matrices[Is] = args), void(), 0)... };
static_cast<void>(dummy);
}
};
int main() {
S<3> s;
s.foo(1, 2, 3);
}
[live demo]
If you can auto generate based on N, I guess that you can write the code to do what you need generically (your comment that you tried to use variadics reinforces that).
The fact that your function is also templated on T unfortunately complicates things a little more than I would like. There are simpler solutions than what I will give, but the only ones I saw require you to either specify the type explicitly, or defer checking to runtime that could be done at compile time. As it stands, the only way I can see to do what you want is to use variadic templates. This gets most of what you want:
template <std::size_t N>
class System {
template <class ... Ts>
void fun(Ts& ts) {
static_assert(sizeof...(Ts) == N, "Wrong number of parameters!");
}
};
I've static asserted rather than enable if, to keep things simpler (and it since it's highly unlikely it will make a difference unless you plan to have another member function named fun... don't do that). Now, this function will only accept being called with N arguments, but it will allow all the types to vary. You want them all to be the same. So we need a bit of TMP.
template <class ... Ts>
struct all_same{};
template <class T>
struct all_same<T> : std::true_type {
using same_type = T;
};
template <class T, class ... Ts>
struct all_same<T, T, Ts...> : all_same<T, Ts...> {};
template <class T1, class T2, class ... Ts>
struct all_same<T1, T2, Ts...> : std::false_type {};
Some classic recursive TMP gets us what we want. Both a true false indicator of whether all the types in the pack are the same, and if they are the same we can access the common type. Once we have a common type, and have verified the size, we can use the pack to initialize an array and loop over it, so we don't have to keep doing annoying variadic style programming inside our function:
template <std::size_t N>
struct System {
template <class ... Ts>
void fun(Ts&... ts) {
static_assert(sizeof...(Ts) == N, "Wrong number of parameters!");
using same = all_same<Ts...>;
static_assert(same::value, "All types must be the same!");
std::array<std::reference_wrapper<typename same::same_type>, N> x{ts...};
for (auto& e : x) { std::cerr << e << std::endl; }
}
};
Modifying this solution to suit your exact needs will require a bit of expertise in C++, and also you'll need to watch our for certain tricky situations, e.g. when you pass both string literals and std::strings or other types that you are used to being implicitly convertible, it will fail. Still, hope this helps get you going. Live example: http://coliru.stacked-crooked.com/a/08ac23da33deb8ef.
A possible solution can be define the function inside the body of the class (en passant: avoid the name system(): can collide with the standard function), using SFINAE, as follows
template <std::size_t N>
class systemClass
{
private:
std::array<FooType, N> matrices;
public:
template<typename T, std::size_t M = N>
typename std::enable_if<M == 1U>::type fun(T & a) { }
template<typename T, std::size_t M = N>
typename std::enable_if<M == 2U>::type fun(T & a, T & b) { }
template<typename T, std::size_t M = N>
typename std::enable_if<M == 3U>::type fun(T & a, T & b, T & c) { }
};
Moreover I would like that the headers functions will be autogenerate based on the template parameter N. I tried to use variadic template but without fortune.
I'm agree with UnholySheep: isn't clear to me what do you exactly want but I suspect that a solution could be a shell script to generate the code.
You can make your function variadic, but only accepting the right number of parameter. It would look like this:
template <std::size_t N>
struct system {
template<typename... Ts>
auto fun(Ts&&... ts) -> std::enable_if_t<(N == sizeof...(Ts))> {
// function content
}
private:
std::array<cv::Mat, N> matrices;
};
The enable if will only allow the function to exist if the number of parameters is equal to N.

How to extract lambda's Return Type and Variadic Parameters Pack back from general template<typename T>

I want to create a templated class or function, that receives a lambda, and puts it internally in std::function<>
Lambda could have any number of input parameters [](int a, float b, ...) std::function<> should correspond to the lambda's operator()'s type
template <typename T>
void getLambda(T t) {
// typedef lambda_traits::ret_type RetType; ??
// typedef lambda_traits::param_tuple --> somehow back to parameter pack Args...
std::function<RetType(Args...)> fun(t);
}
int main() {
int x = 0;
getLambda([&x](int a, float b, Person c){});
}
So I need to somehow extract the Return Type and Parameter Pack
Answer here suggests to use partial spec on lambda's :: operator()
template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())>
{};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
// we specialize for pointers to member function
{
enum { arity = sizeof...(Args) };
// arity is the number of arguments.
typedef ReturnType result_type;
template <size_t i>
struct arg
{
typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
// the i-th argument is equivalent to the i-th tuple element of a tuple
// composed of those arguments.
};
};
But I need a way to convert tuple<> back to parameters pack, to create a proper std::function<> instantiation
template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())>
{};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
// we specialize for pointers to member function
{
using result_type = ReturnType;
using arg_tuple = std::tuple<Args...>;
static constexpr auto arity = sizeof...(Args);
};
template <class F, std::size_t ... Is, class T>
auto lambda_to_func_impl(F f, std::index_sequence<Is...>, T) {
return std::function<typename T::result_type(std::tuple_element_t<Is, typename T::arg_tuple>...)>(f);
}
template <class F>
auto lambda_to_func(F f) {
using traits = function_traits<F>;
return lambda_to_func_impl(f, std::make_index_sequence<traits::arity>{}, traits{});
}
The code above should do what you want. The main idea, as you can see, is to create an integer pack. This is the non-type template equivalent of variadics. I don't know of any technique by which you can use such a pack without calling another function, so typically in these situations with tuples you'll see a nested "impl" function that does all the work. Once you have the integer pack, you expand it while accessing the tuple (works for getting the values too).
On a stylistic note: use using, not typename, especially in template heavy code as the former can alias templates too. And don't use that enum trick to store a static value without it using space; compilers will optimize this out anyhow and just using a static constexpr integer is much clearer.

Varying the Parameter List of an Function Based on Template Parameter?

I am trying to create a template class that executes a user-specified N-ary function with arguments of type C. To do so, I need some way of specifying the type of this function based on the template parameters. The following code illustrates my problem:
template <typename C, size_t N>
class NaryDispatch {
typedef typename std::function<void(/* N parameters of type C& */)> NaryFn;
public:
NaryDispatch(NaryFn f) : m_function(std::forward<NaryFn>(f)) {}
private:
NaryFn m_function;
};
I have been unable to find a way to build the std::function type with a signature of the appropriate arity. I am using C++11 and Boost::MPL extensively so solutions involving either are more than welcome. I have tried to use SFINAE/template parameter deduction on the constructor parameter as follows:
template <
class... Args,
typename std::enable_if<sizeof...(Args) == N, C>::type = 0
>
NaryDispatch(std::function<void(Args&...)> fn) : m_function(std::forward<???>(fn)) {}
As you can see, the issue here is that because I have been unable to determine the type the function will take given the template parameters C and N, I'm unable to determine the type of the class member where the function should be stored.
To simplify my intent a bit, for template parameters C and N, the class constructor should accept (and store in a private member) an std::function that returns void and accepts N parameters of type C&. For example, the following should compile:
NaryDispatch<int, 3> disp([](int a, int b, int c) {});
Thanks in advance for any insights you might offer.
This shouldn't be too hard. Let's start with the top level:
template <typename C, std::size_t N>
struct NaryDispatch
{
// details, see below
using f_type = typename function_maker<C &, N>::type;
template <typename F>
NaryDispatch(F && f) : fn_(std::forward<F>(f)) {}
f_type fn_;
};
Now we just need to implement the trait function_maker:
template <typename T, std::size_t K, typename ...Args>
struct function_maker
{
using type = typename function_maker<T, K - 1, T, Args...>::type;
};
template <typename T, typename ...Args>
struct function_maker<T, 0, Args...>
{
using type = std::function<void(Args...)>;
};
Finally, you might also want to provide some kind of constrained call function. Perhaps like this:
template <typename ...Args,
typename = typename std::enable_if<sizeof...(Args) == N>::type>
void run(Args &&... args)
{
fn_(std::forward<Args>(args)...);
}
Your next problem will be "How do I pass N parameters to the contained std::function?" I think you could simplify substantially by using a dispatcher class template that works with any old list of parameter types:
template <typename...Args>
class Dispatcher {
typedef typename std::function<void(Args...)> Fn;
public:
Dispatcher(Fn f) : m_function(std::move(f)) {}
void operator()(Args...args) {
m_function(std::forward<Args>(args)...);
}
private:
Fn m_function;
};
along with a bit of metaprogramming to calculate the proper Dispatcher specialization to handle N parameters of type C&:
template <typename C, size_t N, typename...Args>
struct NaryDispatch_ {
using type = typename NaryDispatch_<C, N-1, Args..., C&>::type;
};
template <typename C, typename...Args>
struct NaryDispatch_<C, 0, Args...> {
using type = Dispatcher<Args...>;
};
template <typename C, size_t N>
using NaryDispatch = typename NaryDispatch_<C, N>::type;
DEMO AT IDEONE