How can a template argument after variardic arguments be inferred? - c++

I have the following template function:
template <typename...Args, typename Func>
void call(const char *name, Args...args, Func f)
{
f(3);
}
When I try to use it, like
call("test", 1, 2, 3, [=](int i) { std::cout<< i; });
The compiler complains that it cannot infer the template argument Func.
How can this problem be solved, knowing that args can be any type except a function pointer.

From 14.1p11:
A template parameter pack of a function template shall not be followed
by another template parameter unless that template parameter can be deduced from the parameter-type-list
of the function template or has a default argument (14.8.2).
If you want to keep the callable as the last argument, you can use forward_as_tuple:
template <typename...Args, typename Func>
void call(const char *name, std::tuple<Args...> args, Func f)
{
f(3);
}
call("test", std::forward_as_tuple(1, 2, 3), [=](int i) { std::cout<< i; });
We can actually do better by synthesizing the tuple to contain the callable as well:
#include <tuple>
template<typename... Args_F>
void call_impl(const char *name, std::tuple<Args_F... &&> args_f) {
auto &&f = std::get<sizeof...(Args_F) - 1>(args_f);
f(3);
}
template<typename...ArgsF>
void call(const char *name, ArgsF &&...args_f) {
call_impl(name, std::tuple<ArgsF &&...>(std::forward<ArgsF>(args_f)...));
}

Write get_last, which extracts the last element of a parameter pack.
Call it f. Call f.
As an example,
template<typename T0>
auto get_last( T0&& t0 )->decltype(std::forward<T0>(t0))
{
return std::forward<T0>(t0);
}
template<typename T0, typename... Ts>
auto get_last( T0&& t0, Ts&&... ts )->decltype(get_last(std::forward<Ts>(ts)...))
{
return get_last(std::forward<Ts>(ts)...);
}
if you don't care about overload resolution, just calling get_last and treating it like a functor might be enough:
template <typename...Args>
void call(const char *name, Args...&& args)
{
auto&& f = get_last(std::forward<Args>(args)...);
f(3);
}
The next step up would be to do some SFINAE enable_if magic in order to make the call fail to match if you don't pass a valid functor last: however, this is probably overkill.
To detect if the f(3) will work, a simple traits class:
// trivial traits class:
template<typename T>
struct is_type:std::true_type {};
template<typename Functor, typename=void>
struct can_be_called_with_3:std::false_type {}
template<typename Functor>
struct can_be_called_with_3<Functor,
typename std::enable_if<
std::is_type< decltype(
std::declval<Functor>(3)
) >::value
>::type
>:std::true_type {}
which is pretty silly. A fancier traits class would have to be used if your requirements for the passed in type are more complex (say, you want it to be called with the arguments).
Then you augment call with:
template <typename...Args>
auto call(const char *name, Args...&& args)
-> typename std::enable_if<
can_be_called_with_3< decltype( get_last(std::forward<Args>(args)... ) ) >::value
>::type
{ /* body unchanged */ }
which is pretty obtuse.

if you want to vhave a pack of arguments as template you cannot write this in a way you already did:
template <typename...Args, typename Func>
void call(const char *name, Args...args, Func f)
{
f(3);
}
But you can pack them in a std::tuple:
template <typename...Args, typename Func>
void call(const char *name, std::tuple<Args...> args, Func f)
{
f(3);
}
call("test", std::forward_as_tuple(1, 2, 3), [=](int i) { std::cout<< i; });

Related

Passing lambdas as template parameters: what type is actually deduced?

If I pass a lambda as a template parameter, what is the actual type of that parameter that is deduced? I have looked on the VS2017 debugger and the type of this lambda: [](int x) {return x; } is filename::__I2::int<lambda>(int).
The reason I am asking this is because I want to pass a lambda and then create an internal std::function from this. Note that this relates to this answer and why we have to use CTAD to construct an internal std::function instead of just passing the template parameter to a std::function.
As an example, I would like to do something like the following:
template<class Func, class... Args>
void createStdFunc(Func f, Args... args) {
std::function<Func> internalFunc = f; //this does not work
}
//usage
createStdFunc([](int x) {return x; }, 5);
However, this does not work, and I get the error 'initialising' cannot convert from 'Func' to 'std::function<Func>'. I am not sure how the types differ and how they have changed from passing into the function to initialising the std::function. Please note that I do know you can use CTAD from 2017 onwards, but was wondering what a solution for 2014 and before would have been?
In C++14 you can use return type deduction to figure out function signature, this implies that types of arguments passed into createStdFunc match:
template<class Func, class... Args>
void createStdFunc(Func f, Args... args) {
std::function<std::result_of_t<Func(Args...)> (Args...)> internalFunc{f}; //this does work
}
My way
#include <iostream>
#include <functional>
template <typename R, typename T, typename ... As>
constexpr std::function<R(As...)> getFuncType (R(T::*)(As...) const);
template <typename F, typename ... As>
void createStdFunc (F const & f, As ... as)
{
decltype(getFuncType(&F::operator())) internalFunc { f };
internalFunc(as...);
}
int main ()
{
createStdFunc([](int x) { std::cout << x << std::endl; }, 5);
}
Maybe also through a using
template <typename F>
using funcType = decltype(getFuncType(&F::operator()));
template <typename F, typename ... As>
void createStdFunc (F const & f, As ... as)
{
funcType<F> internalFunc { f };
internalFunc(as...);
}
The problem inside your code is that Func is not a function type. It's the type of the lambda. Lambdas compile down to something like this:
// equivalent:
// auto my_lambda = [](int v){ return v; };
struct /* unnamed */ {
auto operator()(int v) const { return v; }
} my_lambda;
The solution would be to extract the type of the operator() from the closure type:
using my_lambda_t = decltype(my_lambda);
// type: int(my_lambda_t::*)(int) const;
auto call_operator = &decltype(my_lambda_t)::operator();
Then, from the type of the operator(), you can deduce the type of the arguments and the return type:
template<typename>
struct extract_types {};
template<typename R, typename C, typename... Args>
struct extract_types<R(C::*)(Args...) const> {
using result = R;
using args_types = std::tuple<Args...>;
};
Generalized versions of this pattern is shipped in Boost.CallableTraits
You can write a simple trait to generalize callable types. If you handle both function pointers and anything with operator() (both const and non-const) you should be able to cover most use cases.
#include <tuple>
// For callable types
template<class T>
struct func_type : func_type<decltype(&T::operator())>{};
// For callable types' member functions (including `operator()`)
template<class T, class R, class ... Args >
struct func_type<R (T::*)(Args...) const> : func_type<R(*)(Args...)> {};
// For function pointers
template<class R, class ... Args >
struct func_type<R (*)(Args...)> {
using type = R(Args...);
using result = R;
using args = std::tuple<Args...>;
};
template<class T>
using func_type_t = typename func_type<T>::type;
func_type_t<T> should then give you a function type for most callable types T. Example uses :
#include <functional>
template<class Func, class... Args>
void createStdFunc(Func f, Args... args) {
// Replaced `Func` with `func_type_t<Func>`
std::function<func_type_t<Func>> internalFunc = f;
}
int foo(int x) { return x; }
struct bar {
int operator()(int x) { return x; };
};
int main()
{
// With lambda expression
createStdFunc([](int x) {return x; }, 5);
// With function pointer
createStdFunc(foo, 5);
// With std::function
std::function<int(int)> std_func = [](int x) {return x; };
createStdFunc(std_func, 5);
// With a functor
createStdFunc(bar{}, 5);
}
The std::function template expects as its argument a function type from which it infers the return and parameter type for the callable to wrap. The closure type of a lambda expression is a callable, but it's not a function type.
C++17 introduced deduction guides for std::function which allow the correct type to be deduced from any callable argument. Pre C++17, you could use a set of helper templates to deduce the correct type, for example:
template <typename F>
struct deduce_func_type_helper;
template <typename R, typename... Args>
struct deduce_func_type_helper<R(&)(Args...)>
{
using type = std::function<R(Args...)>;
};
template <typename R, typename... Args>
struct deduce_func_type_helper<R(*)(Args...)> : deduce_func_type_helper<R(&)(Args...)> {};
template <typename C, typename R, typename... Args>
struct deduce_func_type_helper<R(C::*)(Args...)> : deduce_func_type_helper<R(&)(Args...)> {};
template <typename C, typename R, typename... Args>
struct deduce_func_type_helper<R(C::*)(Args...) const> : deduce_func_type_helper<R(&)(Args...)> {};
template <typename C, typename R, typename... Args>
struct deduce_func_type_helper<R(C::*)(Args...) volatile> : deduce_func_type_helper<R(&)(Args...)> {};
template <typename F>
struct deduce_func_type_helper<F&> : deduce_func_type_helper<std::remove_cv_t<F>> {};
template <typename F>
struct deduce_func_type_helper<F&&> : deduce_func_type_helper<std::remove_cv_t<F>> {};
template <typename F>
struct deduce_func_type_helper : deduce_func_type_helper<decltype(&F::operator())> {};
template <typename F>
using func_type_t = typename deduce_func_type_helper<F>::type;
live example here
Note that above example is not complete; it's missing some specializations, e.g., for all possible combinations of const, volatile, and different ref qualifiers. So this can get quite verbose, you will probably want to go with C++17 if you can…

How to overload a template function depending on argument's call operator args or existence?

Note: I am working with VS2013 so the C++11 features available are limited.
I am having trouble with overloading a template function depending on if the argument type is callable or not and, ideally, if the arguments match a specific pattern.
Here is a very simplified example of the code I have, my problem being how to implement update_callabe() overloads :
template< class T, class... Args >
void update_callable( const std::vector<T>& objects, Args&&... args ); // 1: How to implement this?
template< class T, class... UpdateArgs>
class Controller
{ //...
virtual void update( T&, UpdateArgs... args ) = 0;
public:
template< class IterBegin, class IterEnd, class... Args >
void update_batch( IterBegin first, IterEnd last, Args&&... args )
{
std::for_each( first, last, [&]( T& object ){ update(object, args...); }
}
//...
};
template< class T, class... UpdateArgs >
class Group
{
public:
using ControllerType = Controller<T,UpdateArgs...>;
void add( ControllerType& controler ) { /* ... */ m_controllers.emplace_back( &controller ); }
template< class... Args >
void update( Args&&... args )
{
update_callable(m_objects, std::forward<Args>(args)); // 2
for( auto* controller : m_controllers )
{
controller->update_batch( begin(m_objects), end(m_objects), std::forward<Args>(args)); // 3
}
}
private:
std::vector<T> m_objects;
std::vector<ControllerType*> m_controllers;
//...
};
A. What I want to achieve with update_callabe() overloads (in priority order):
if T is callable with Args arguments, then call all T objects with the arguments.
if T is not callable with Args arguments, then do exactly nothing.
B. That would be ok for me, but ideally I would like update_callabe() overloads that follow these rules (in priority order):
if T is callable with Args arguments, then call all T objects with the arguments.
if T is callable with NO arguments, then call all T objects with no arguments.
if T is not callable with Args arguments nor NO arguments, then do exactly nothing.
I have tried with enable_if, conditional and several advanced techniques but I'm no expert (yet) so I'm failing to express this correctly.
Some notes about the example here:
it's a simplified example, I didn't try to compile it but it is close to my code;
(2) basically we want to call the default update of the objects stored if the type of the objects provide one, "default update" meaning here the call operator either with arguments from the update context or with no arguments if the type don't need them;
(3) there is a second update loop for "controller" objects that can manipulate externally the stored objects;
When I want if/else if/else-like behavior at compile time, I use a trick like this:
template <unsigned int N>
struct priority_helper
: public priority_helper<N-1> {};
template <>
struct priority_helper<0U> {};
template <unsigned int N>
using priority = int priority_helper<N>::*;
constexpr priority<0> by_priority{};
template <typename Arg>
auto do_thing_detail(Arg&& arg, priority<1>)
-> typename std::enable_if<cond1<Arg>::value>::type
{ /*...*/ }
template <typename Arg>
auto do_thing_detail(Arg&& arg, priority<2>)
-> typename std::enable_if<cond2<Arg>::value>::type
{ /*...*/ }
template <typename Arg>
void do_thing_detail(Arg&& arg, priority<3>)
{ /*...*/ }
template <typename Arg>
void do_thing(Arg&& arg)
{ do_thing_detail(std::forward<Arg>(arg), by_priority); }
This would also work using the simpler types priority_helper<N>* instead of int priority_helper<N>::*, but then the larger values of N would be the preferred overloads, since pointer-to-derived is more specific than pointer-to-base. By using the pointer to member, the implicit conversions and therefore overload preferences go the other way around (pointer-to-member-of-base converts to pointer-to-member-of-derived).
So for your problem, after defining priority<N> as above...
template < class T, class... Args >
auto update_callable_detail(
priority<1>,
const std::vector<T>& objects,
Args&& ... args )
-> decltype(std::declval<const T&>()(std::forward<Args>(args)...), void())
{
for ( const T& obj : objects )
obj( std::forward<Args>(args)... );
}
template < class T, class... Args >
auto update_callable_detail(
priority<2>,
const std::vector<T>& objects,
Args&& ... )
-> decltype(std::declval<const T&>()(), void())
{
for ( const T& obj : objects )
obj();
}
template < class T, class... Args >
void update_callable_detail(
priority<3>,
const std::vector<T>&,
Args&& ... )
{
}
template < class T, class... Args >
void update_callable( const std::vector<T>& objects, Args&& ... args )
{
update_callable_detail( by_priority, objects, std::forward<Args>(args)... );
}
In this case it just seemed simpler to use SFINAE directly in the overload declarations, rather than do anything with std::result_of (especially since the C++11 requirements for result_of aren't as helpful as the C++14 version). Whenever the deduced arguments for T and Args result in an illegal expression in the decltype, that overload is thrown out during overload resolution.
Doable with a couple of traits and some tag dispatching (Demo at Coliru). First, define traits that determine if T is either callable with the specified argument types:
template <typename T, typename... Args>
struct callable_with_args_ {
template <typename U=T>
static auto test(int) ->
decltype((void)std::declval<U>()(std::declval<Args>()...), std::true_type());
static auto test(...) -> std::false_type;
using type = decltype(test(0));
};
template <typename T, typename... Args>
using callable_with_args = typename callable_with_args_<T, Args...>::type;
or with no arguments:
template <typename T>
struct callable_without_args_ {
template <typename U=T>
static auto test(int) ->
decltype((void)std::declval<U>()(), std::true_type());
static auto test(...) -> std::false_type;
using type = decltype(test(0));
};
template <typename T>
using callable_without_args = typename callable_without_args_<T>::type;
Then implement a two-level tag dispatch to get the precedence that you want:
template < class T >
void update_callable_no_args(std::false_type, const std::vector<T>&) {}
template < class T >
void update_callable_no_args(std::true_type, const std::vector<T>& objects) {
for (auto&& i : objects) {
i();
}
}
template< class T, class... Args >
void update_callable_args(std::false_type,
const std::vector<T>& objects,
Args&&... ) {
update_callable_no_args(callable_without_args<T const&>(), objects);
}
template< class T, class... Args >
void update_callable_args(std::true_type,
const std::vector<T>& objects,
Args&&... args ) {
for (auto&& i : objects) {
i(args...);
}
}
template< class T, class... Args >
void update_callable( const std::vector<T>& objects, Args&&... args ) {
using callable = callable_with_args<
T const&, typename std::add_lvalue_reference<Args>::type...
>;
update_callable_args(callable(), objects, std::forward<Args>(args)...);
}
Note that I coerce the argument types to lvalue references, to avoid having any of the callables "eat" rvalue reference arguments causing later callables to see moved-from objects. If you want the rvalues to possibly be moved from, remove the coercion in update_callable:
using callable = callable_with_args<
T const&, Args&&...
>;
and forward them to each callable in update_callable_args:
for (auto&& i : objects) {
i(std::forward<Args>(args)...);
}
VS2013 at least seems to compile it properly.
Here is a partial solution using expression SFINAE (not sure if your VC version supports that)
template<class T>
auto update_callable(const std::vector<T>&, ...)
-> void
{
}
template< class T, class... Args>
auto update_callable( const std::vector<T>& objects, Args&&... args)
-> decltype(std::declval<T>()(std::forward<Args>(args)...))
{
for (auto&& elem : objects)
elem(std::forward<Args>(args)...);
}
template< class T, class... Args>
auto update_callable( const std::vector<T>& objects, Args&&... args)
-> decltype(std::declval<T>()())
{
for (auto&& elem : objects)
elem();
}
It's a partial solution because the varargs ... argument of the first overload only supports POD arguments (which is why I pasted in the std::vector<T> argument since a vector isn't POD).
You can test it like this:
struct N {};
struct Z
{
void operator()() const
{ std::cout << "Z(), "; }
};
struct T
{
void operator()(int x, int y) const
{ std::cout << "T(," << x << "," << y << "), "; }
};
int main()
{
auto vN = std::vector<N>(1);
auto vZ = std::vector<Z>(2);
auto vT = std::vector<T>(3);
update_callable(vN, 1, 2);std::cout << "end of 1st\n";
update_callable(vZ, 1, 2);std::cout << "end of 2nd\n";
update_callable(vT, 1, 2);std::cout << "end of 3rd\n";
}
Live Example that outputs
end of 1st
Z(), Z(), end of 2nd
T(1,2), T(1,2), T(1,2), end of 3rd

How can I generate as many parameters as is the arity of a function?

Suppose I have the following function, that takes a function as a parameter.
template <typename F>
void test_func(F f)
{
// typedef typename function_traits<F>::return_type T;
typedef int T;
std::mt19937 rng(std::time(0));
std::uniform_int_distribution<T> uint_dist10(0, std::numeric_limits<T>::max());
f(uint_dist10(rng), uint_dist10(rng)); // Problem!
}
Usage would be:
int foo(int, int) { return 0; }
int bar(int, int, int, int) { return 0; }
int main()
{
test_func(foo);
// test_func(bar);
}
Just like foo and bar, I have several functions that return T, and take some amount of parameters of type T. I would like test_func to generate as many calls to my RNG as the function f takes parameters. In other words, we can assume T is always an integer type, and that each parameter will be the same, i.e. a function call to an RNG.
Using function_traits (such as the ones in Boost), I can fetch the return type of F, and that helps a little. Roughly, my question is
How can I generate a needed amount of function calls so that it matches the arity of the function F?
Before C++11, I would have looked at Boost.Preprocessor, or maybe relied on template specialization. Is there a nicer way of doing it now?
First define a meta function called arity to compute arity of the function (it is just a simple implementation; can be improved to compute arity of functors also. See my answer here.):
template<typename F>
struct arity;
template<typename R, typename ...Args>
struct arity<R (*)(Args...)>
{
static const std::size_t value = sizeof ... (Args);
};
then define another meta function called genseq to generate a compile time sequence of integral values:
template<int ... N>
struct seq
{
using type = seq<N...>;
template<int I>
struct push_back : seq<N..., I> {};
};
template<int N>
struct genseq : genseq<N-1>::type::template push_back<N-1> {};
template<>
struct genseq<0> : seq<> {};
template<int N>
using genseq_t = typename genseq<N>::type; //Just a friendly alias!
then a function invoker as:
template<typename F, typename ArgEvaluator, int ...N>
void invoke(seq<N...>, F f, ArgEvaluator arg_evaluator)
{
using arg_type = decltype(arg_evaluator());
constexpr std::size_t arity = sizeof ... (N);
arg_type args[] { (N, arg_evaluator()) ... }; //enforce order of evaluation
f( args[N] ... );
}
And then your code would become this:
template <typename F>
void test_func(F f)
{
// typedef typename function_traits<F>::return_type T;
typedef int T;
std::mt19937 rng(std::time(0));
std::uniform_int_distribution<T> uint_dist10(0, std::numeric_limits<T>::max());
//f(uint_dist10(rng), uint_dist10(rng)); // Problem!
auto arg_evaluator = [&]() mutable { return uint_dist10(rng); };
invoke(genseq_t<arity<F>::value>(), f, arg_evaluator);
}
Here is a sample demo.
Hope that helps.
No need for complicated meta calculations.
template <typename Ret, typename ... T>
void test_func (Ret f (T...))
{
std::mt19937 rng(std::time(0));
f((std::uniform_int_distribution<T>(0, std::numeric_limits<T>::max())(rng))...);
}
int moo(int, int, int){ return 0; }
int main ()
{
test_func(moo);
}
To support functors one needs a bit longer implementation, still not too complicated:
// separate arguments type from function/functor type
template <typename F, typename ... T>
void test_func_impl (F f)
{
std::mt19937 rng(std::time(0));
f((std::uniform_int_distribution<T>(0, std::numeric_limits<T>::max())(rng))...);
}
// overload for a straight function
template <typename Ret, typename ... T>
void test_func (Ret f (T...))
{
test_func_impl<decltype(f), T...>(f);
}
// forwarder for a functor with a normal operator()
template <typename F, typename Ret, typename... T>
void test_func_for_functor (F f, Ret (F::*)(T...))
{
test_func_impl<F, T...>(f);
}
// forwarder for a functor with a const operator()
template <typename F, typename Ret, typename... T>
void test_func_for_functor (F f, Ret (F::*)(T...)const)
{
test_func_impl<F, T...>(f);
}
// overload for anything that has operator()
template <typename F>
void test_func (F f)
{
test_func_for_functor(f, &F::operator());
}

C++11 variable number of arguments, same specific type

Question is simple, how would I implement a function taking a variable number of arguments (alike the variadic template), however where all arguments have the same type, say int.
I was thinking about something alike this;
void func(int... Arguments)
Alternatively wont a recursive static assert on the types work?
A possible solution is to make the parameter type a container that can be initialized by a brace initializer list, such as std::initializer_list<int> or std::vector<int>. For example:
#include <iostream>
#include <initializer_list>
void func(std::initializer_list<int> a_args)
{
for (auto i: a_args) std::cout << i << '\n';
}
int main()
{
func({4, 7});
func({4, 7, 12, 14});
}
Here's a version that removes the function from the overload set, instead of giving a static_assert. This is allows you to provide other overloads of the function that could be used when the types aren't all the same, rather than a fatal static_assert that can't be avoided.
#include <type_traits>
template<typename... T>
struct all_same : std::false_type { };
template<>
struct all_same<> : std::true_type { };
template<typename T>
struct all_same<T> : std::true_type { };
template<typename T, typename... Ts>
struct all_same<T, T, Ts...> : all_same<T, Ts...> { };
template<typename... T>
typename std::enable_if<all_same<T...>::value, void>::type
func(T...)
{ }
If you want to support perfect forwarding you probably want to decay the types before checking them, so that the function will accept a mix of lvalue and rvalue arguments as long as they have the same type:
template<typename... T>
typename std::enable_if<all_same<typename std::decay<T>::type...>::value, void>::type
func(T&&...)
{ }
Alternatively, if you have a general purpose trait for testing the logical conjunction you can do it using std::is_same instead of writing your own all_same:
template<typename T, typename... Ts>
typename std::enable_if<and_<is_same<T, Ts>...>::value, void>::type
func(T&&, Ts&&...)
{ }
Because this requires at least one argument you'd also need another overload to support the zero-argument case:
void func() { }
The and_ helper can be defined like so:
template<typename...>
struct and_;
template<>
struct and_<>
: public std::true_type
{ };
template<typename B1>
struct and_<B1>
: public B1
{ };
template<typename B1, typename B2>
struct and_<B1, B2>
: public std::conditional<B1::value, B2, B1>::type
{ };
template<typename B1, typename B2, typename B3, typename... Bn>
struct and_<B1, B2, B3, Bn...>
: public std::conditional<B1::value, and_<B2, B3, Bn...>, B1>::type
{ };
I think you can do this by specifying a concrete type when chewing your arguments out of the argument pack. Something like:
class MyClass{};
class MyOtherClass{};
void func()
{
// do something
}
template< typename... Arguments >
void func( MyClass arg, Arguments ... args )
{
// do something with arg
func( args... );
// do something more with arg
}
void main()
{
MyClass a, b, c;
MyOtherClass d;
int i;
float f;
func( a, b, c ); // compiles fine
func( i, f, d ); // cannot convert
}
In the generic case void func( MyClass arg, Arguments ... args ) would become void func( arg, Arguments ... args ) with a template type T.
#Skeen
How about this?
template <typename T>
void func_1(std::initializer_list<T>&& a) {
// do something
}
template <typename... T>
void func(T&&... a) {
func_1({std::forward<T>(a)...});
}
int main() {
func(1, 2, 3);
// func(1, 2, 3, 4.0); // OK doesn't compile
}
If you don't want to use brace-based initializer_list/vector and want to keep the arguments separate in form of argument pack, then below solution checks it at compile time using recursive static_asserts:
#include<type_traits>
template<typename T1, typename T2, typename... Error>
struct is_same : std::false_type {};
template<typename T, typename... Checking>
struct is_same<T, T, Checking...> : is_same<T, Checking...> {};
template<typename T>
struct is_same<T,T> : std::true_type {};
template<typename... LeftMost>
void func (LeftMost&&... args)
{
static_assert(is_same<typename std::decay<LeftMost>::type...>::value,
"All types are not same as 'LeftMost'");
// ...
}
int main ()
{
int var = 2;
func(1,var,3,4,5); // ok
func(1,2,3,4.0,5); // error due to `static_assert` failure
}
Actually this solution would check all the arguments with respect to the first argument. Suppose it was double then everything would be checked against double.
Because I don't think I saw this solution, you could write a specific function for every type (in your case, just int) then a forwarding function taking variadic argument types.
Write each specific case:
then for each specific case:
// only int in your case
void func(int i){
std::cout << "int i = " << i << std::endl;
}
Then your forwarding function like this:
template<typename Arg0, typename Arg1 typename ... Args>
void func(Arg0 &&arg0, Arg1 &&arg1, Args &&... args){
func(std::forward<Arg0>(arg0));
func(std::forward<Arg1>(arg1), std::forward<Args>(args)...);
}
This is good because it is expandable for when you want to accept maybe another type too.
Used like this:
int main(){
func(1, 2, 3, 4); // works fine
func(1.0f, 2.0f, 3.0f, 4.0f); // compile error, no func(float)
}

Is it possible to retrieve the argument types from a (Functor member's) function signature for use in a template?

Assume you have a functor:
struct MyFunctor
{
bool operator ()( int value )
{
return true;
}
};
Is it possible to retrieve a functor's member's argument type for use within your template? The following is a use of this mythical functionality:
template < typename FunctorType >
bool doIt( FunctorType functor, typename FunctorType::operator()::arg1 arg )
{
return functor( arg );
}
Is there a valid syntax that would substitute for my mythical FunctorType::operator()::arg1 ?
If you know the item is a functor, then you can just grab its operator(), like so:
#include <iostream>
template <unsigned Idx, typename... T>
struct pick
{
static_assert(Idx < sizeof...(T), "cannot index past end of list");
};
template <typename T, typename... TRest>
struct pick<0U, T, TRest...>
{
typedef T result;
};
template <unsigned Idx, typename T, typename... TRest>
struct pick<Idx, T, TRest...>
{
typedef typename pick<Idx-1, TRest...>::result result;
};
template <typename Func>
struct func_traits;
template <typename TObj, typename R, typename... TArgs>
struct func_traits<R (TObj::*)(TArgs...)>
{
typedef R result_type;
template <unsigned Idx>
struct argument
{
typedef typename pick<Idx, TArgs...>::result type;
};
};
template <typename Func,
typename Traits = func_traits<Func>,
typename R = typename Traits::result_type,
typename Arg0 = typename Traits::template argument<0>::type,
typename Arg1 = typename Traits::template argument<1>::type
>
void foo(Func f)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
};
struct thing
{
void operator()(long, int*) { }
};
int main()
{
foo(&thing::operator());
}
For me, that program prints out:
void foo(Func) [with Func = void (thing::*)(long int, int*), Traits = func_traits<void (thing::*)(long int, int*)>, R = void, Arg0 = long int, Arg1 = int*]
The key point being that Arg0 and Arg1 are long and int*, respectively.
No there is not. The most elegant way to do this would be to either require your functors to provide a typedef for the argument-type, or to introduce a traits-class. The latter is useful if you want your template to work with functors and functions.
Alternatively, you can just make the argument type a second template parameter:
template < typename FunctorType, class ArgumentType >
bool doIt( FunctorType functor, ArgumentType arg )
{
return functor( arg );
}
The compiler will still complain if ArgumentType does not match the type required by the functor.
You can sort of do it in C++0x
template <typename... Args>
struct Function {
typedef std :: tuple <Args...> args;
void call () (Args... args);
}
template <typename... Args>
void do_it (Function<Args...>::args:: SOMETHING :: type t, Args... args) {
something (t)
Function <Args...> :: call (args...);
}
Here I give a C++11 update to #BjörnPollex (correct) answer.
Going back the question, you want to specify the second argument of doIt explicitly mainly to restrict what can be passed. In C++11 you can imply this restriction without knowing explicitly the argument type of the functor (which is not well defined if the functor overloaded anyway).
template < typename FunctorType, class ArgumentType >
auto doIt( FunctorType functor, ArgumentType arg ) -> decltype(bool(functor(arg)))
{
return functor( arg );
}
(the conversion to bool may not be even necessary, I put it here because it seem that you really want the return type to be bool).
This doIt (template) function will take any argument that is possibly compatible with a functor argument (and also convertible to bool). If the argument passed is not compatible the function will not even exist at all, and will produce an elegant "doIt function not found" compiler error.
One can go one step more by using perfect forward to make doIt exactly equivalent to functor(arg):
template < typename F, class A >
auto doIt( F&& f, A&& a ) -> decltype(bool(std::forward<F>(f)(std::forward<A>(a))))
{
return std::forward<F>(f)( std::forward<A>(a) );
}