Variadic template method specialization - c++

This is the code I currently have:
class Foo
{
public:
template<typename T, typename... Args>
void Function(T t1, Args... args){
// Definition
}
private:
template<typename T>
void Function(T t1){
// Definition
}
};
#include "header.h"
int main()
{
Foo foo;
foo.Function(1, 2, 3, 4, 5);
return 0;
}
Works just fine. When I try to separate the definition to source.cpp, the gcc starts complaining. I know I have to specialize the templates in order to separate the definition, so I tried adding the code below to the header file:
template<>
void Foo::Function<int, int...>(int t1, int... args);
template<>
void Foo::Function<int>(int);
but without success. What am I missing
edit: gcc error messages:
header.h:15:28: error: expansion pattern ‘int’ contains no argument
packs void Foo::Function(int t1, int... args);
header.h:15:48: error: expansion pattern ‘int’ contains no argument
packs void Foo::Function(int t1, int... args);

You can't use int... as a parameter pack, and so this doesn't work. In addition, to separate the source from the definition, you have to fully specify the template, so int... wouldn't work even if that syntax were allowed.
Ways to get around this.
1. Make Function accept an initializer list.
We can write function so that it accepts an initializer list of ints:
#include <initializer_list>
class Foo {
public:
void Function(int t1, std::initializer_list<int> t2);
};
void Foo::Function(int t1, std::initializer_list<int> t2) {
for(int i : t2) {
// stuff
}
}
Now, you can call Function pretty easily, and it's not even templated:
Foo f;
f.Function(10, {1, 2, 3, 4, 5});
If there are other places you're using templates, you can expand a parameter pack directly into the initializer list:
template<class... Args>
void invoke_foo(Foo& f, int first, Args... rest) {
f.Function(first, {rest...});
}
2. Use SFINAE to disable all non-int overloads. We can disable all overloads of Foo::Function that don't only accept ints
#include <type_traits>
class Foo {
public:
// Requires C++17 for std::conjunction
// You could write your own std::conjunction too if you'd prefer
template<class... Args>
auto Function(int t1, Args... t2)
-> std::enable_if_t<std::conjunction<std::is_same<Args, int>...>::value>
{
// stuff
}
};
The downside to this is that non-integral values won't automatically be converted to int.

There is better way to do it.
First of all it looks like you want to force same type of all arguments (this is done by std::initializer_list in accepted answer). This can be foreced by providing extra explicit argument:
class Foo
{
public:
template<typename T, typename... Args>
void Function(T t1, T t2, Args... args)
{
LOG;
this->Function(t1);
this->Function(t2, args...);
}
private:
template<typename T>
void Function(T t1)
{
LOG << VAR(t1);
}
};
template<>
void Foo::Function<int>(int x)
{
LOG << " Spec" << VAR(x);
}
As you can see it is enough if you provide specialization of method for single argument.
Live demo

Related

Expand function argument pack as a non-type parameter pack argument?

Why doesn't the following compile:
template <int...is> void g() {}
template <typename...Ts> void f(Ts...ts) {
g<ts...>();
}
int main() {
f(1,2);
}
it fails with
error: no matching function for call to 'g<ts#0, ts#1>()'
| g<ts...>();
| ~~~~~~~~^~
I understand that in general this is not possible since f can be called with anything.
I am curious if there is a way to make this work in cases such as here where the compiler clearly sees the compile time constant arguments in the call to f?
There is this way to do it:
f(std::integral_constant<int, 1>{}, std::integral_constant<int, 2>{});
// Or your own structs
template<int V>
struct i_t {
constexpr operator int() const { return V; }
};
template<int V>
inline constexpr i_t<V> i;
f(i<1>, i<2>);
Since std::integral_constant<T, N>::operator T() just returns N so is a constant expression, and when you have g<ts...>, it calls operator int on each argument in the pack, which doesn't use the value of any ts.
You can only use typename or class with parameter packs, so int s wont work. https://en.cppreference.com/w/cpp/language/parameter_pack
There are ways to only make f work for only ints though, I made this example for you. If you have any questions let me know.
#include <utility>
#include <type_traits>
// Create a constexpr (evaluated at compile time) to check
// if all arguments are ints.
template <typename... Ts>
constexpr bool are_all_ints()
{
// conjunction is a 'logical and' when doing template metaprogramming
// is_same checks the types , the syntax is what it is to expand for all template parameters
return std::conjunction_v<std::is_same<int, Ts>...>;
}
// now you can either use a static assert to give a compile time warning
template <typename... Ts>
void g(Ts&&... values)
{
static_assert(are_all_ints<Ts...>(), "this function only works with ints");
}
// or you can chose to completely hide the function
// f2 for anything that doesn't have all ints.
template <typename... Ts>
std::enable_if_t<are_all_ints<Ts...>(), void> g2(Ts&&... values)
{
}
template <typename... Ts>
void f(Ts&&... ts)
{
g(std::forward<Ts>(ts)...);
}
template <typename... Ts>
void f2(Ts&&... ts)
{
g2(std::forward<Ts>(ts)...);
}
int main()
{
f(1, 2);
//f(1.0, 2.0);
//f2(1.0, 2.0);
}

Template pack expansion to apply a function to consecutive pairs of parameters

I am trying to create a variadic template function which would call a function to consecutive pairs of arguments.
The desired function signature would be:
template <typename ...Ts>
void apply(Ts &...args);
When called with apply(t1, t2, t3) the function should make a sequence of calls func(t1, t2)and func(t2, t3), where func is a function with signature:
template <typename L, typename R>
void func(L &left, R &right);
The order of operations is not really relevant in my context. The function has to be able to modify objects left and right, hence passed by reference. I cannot simply use polymorphic access through a base class pointer, since the objects have different class templates, a shared class cannot really be taken out.
Is it possible to achieve such a sequence of calls via a variadic template function? None of the pack expansion and fold expression examples that I've seen seem to cover such a scenario. Or should I pass my objects in a different fashion?
My initial attempt, included below (with some details omitted), packed all template parameters into a tuple, and then used a ‘const for-loop’ to ‘loop’ through the tuple elements. However, I soon came to realize that this approach would not work, because the lambda in the const-for loop invokes operator() const and therefore cannot modify the passed objects.
The code I was using does make the desired sequence of calls, but the objects are not modified (set_something() is not a const function). I had to resort to using a wrapper function with different numbers of template parameters, and making the calls to func manually.
template <std::size_t Begin, typename Callable, std::size_t... I>
constexpr void const_for_impl(Callable &&func, std::index_sequence<I...>) {
(func(std::integral_constant<std::size_t, Begin + I>{}), ...);
}
template <std::size_t Begin, std::size_t End, typename Callable>
constexpr void const_for(Callable &&func) {
const_for_impl<Begin>(std::forward<Callable>(func),
std::make_index_sequence<End - Begin>{});
};
template <typename... Ts>
void apply(Ts *... args) {
auto tuple = std::make_tuple(std::forward<Ts>(args)...);
const_for<0, sizeof...(args) - 1>(
[&](auto I) { func((std::get<I>(tuple)), (std::get<I + 1>(tuple))); });
};
template <typename L, typename R>
void func(L &l, R &r) {
// Validate with some type traits
static_assert(has_some_property<L>::value);
static_assert(has_another_property<R>::value);
// Get a shared pointer to something common
auto common = std::make_shared<typename something_common<L, R>::type>();
l.set_something(common);
r.set_something(common);
};
// Application scenario
int main() {
ComplexObjectA<SomeType, SomeParameter> a;
ComplexObjectB<AnotherType, AnotherParameter> b;
ComplexObjectC c;
apply(a, b, c);
return 0;
}
So, what's the problem? Simple fold-like template (and remember that template pattern-matching goes in reverse!)
template<typename T1, typename T2>
void apply(T1 &&t1, T2 &&t2) { func(t1, t2); }
template<typename T1, typename T2, typename... Ts>
void apply(T1 &&t1, T2 &&t2, Ts &&...ts) {
func(t1, t2);
return apply(t2, ts...);
}
Or, more precise, it should actually look as (thanks #MaxLanghof):
void apply(T1 &&t1, T2 &&t2) {
func(std::forward<T1>(t1), std::forward<T2>(t2));
}
template<typename T1, typename T2, typename... Ts>
void apply(T1 &&t1, T2 &&t2, Ts &&...ts) {
func(std::forward<T1>(t1), t2);
return apply(std::forward<T2>(t2), std::forward<TS>(ts)...);
}
An alternative (c++14) approach:
#include <utility>
#include <utility>
#include <tuple>
#include <iostream>
template <typename L, typename R>
void func(L &left, R &right) {
std::cout << left << " " << right << std::endl;
}
template <typename Tup, std::size_t... Is>
void apply_impl(Tup&& tup, std::index_sequence<Is...>) {
int dummy[] = { 0, (static_cast<void>(func(std::get<Is>(tup), std::get<Is + 1>(tup))), 0)... };
static_cast<void>(dummy);
}
template <typename ...Ts>
void apply(Ts &...args) {
apply_impl(std::forward_as_tuple(args...), std::make_index_sequence<sizeof...(Ts) - 1>{});
}
int main() {
int arr[] = {0, 1, 2, 3};
apply(arr[0], arr[1], arr[2], arr[3]);
}
Output:
0 1
1 2
2 3
[online example]
To make it c++11 compliant one would need to use one of the available integer_sequence implementations.

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)
}

How to store variadic template arguments?

Is it possible to store a parameter pack somehow for a later use?
template <typename... T>
class Action {
private:
std::function<void(T...)> f;
T... args; // <--- something like this
public:
Action(std::function<void(T...)> f, T... args) : f(f), args(args) {}
void act(){
f(args); // <--- such that this will be possible
}
}
Then later on:
void main(){
Action<int,int> add([](int x, int y){std::cout << (x+y);}, 3, 4);
//...
add.act();
}
To accomplish what you want done here, you'll have to store your template arguments in a tuple:
std::tuple<Ts...> args;
Furthermore, you'll have to change up your constructor a bit. In particular, initializing args with an std::make_tuple and also allowing universal references in your parameter list:
template <typename F, typename... Args>
Action(F&& func, Args&&... args)
: f(std::forward<F>(func)),
args(std::forward<Args>(args)...)
{}
Moreover, you would have to set up a sequence generator much like this:
namespace helper
{
template <int... Is>
struct index {};
template <int N, int... Is>
struct gen_seq : gen_seq<N - 1, N - 1, Is...> {};
template <int... Is>
struct gen_seq<0, Is...> : index<Is...> {};
}
And you can implement your method in terms of one taking such a generator:
template <typename... Args, int... Is>
void func(std::tuple<Args...>& tup, helper::index<Is...>)
{
f(std::get<Is>(tup)...);
}
template <typename... Args>
void func(std::tuple<Args...>& tup)
{
func(tup, helper::gen_seq<sizeof...(Args)>{});
}
void act()
{
func(args);
}
And that it! So now your class should look like this:
template <typename... Ts>
class Action
{
private:
std::function<void (Ts...)> f;
std::tuple<Ts...> args;
public:
template <typename F, typename... Args>
Action(F&& func, Args&&... args)
: f(std::forward<F>(func)),
args(std::forward<Args>(args)...)
{}
template <typename... Args, int... Is>
void func(std::tuple<Args...>& tup, helper::index<Is...>)
{
f(std::get<Is>(tup)...);
}
template <typename... Args>
void func(std::tuple<Args...>& tup)
{
func(tup, helper::gen_seq<sizeof...(Args)>{});
}
void act()
{
func(args);
}
};
Here is your full program on Coliru.
Update: Here is a helper method by which specification of the template arguments aren't necessary:
template <typename F, typename... Args>
Action<Args...> make_action(F&& f, Args&&... args)
{
return Action<Args...>(std::forward<F>(f), std::forward<Args>(args)...);
}
int main()
{
auto add = make_action([] (int a, int b) { std::cout << a + b; }, 2, 3);
add.act();
}
And again, here is another demo.
You can use std::bind(f,args...) for this. It will generate a movable and possibly copyable object that stores a copy of the function object and of each of the arguments for later use:
#include <iostream>
#include <utility>
#include <functional>
template <typename... T>
class Action {
public:
using bind_type = decltype(std::bind(std::declval<std::function<void(T...)>>(),std::declval<T>()...));
template <typename... ConstrT>
Action(std::function<void(T...)> f, ConstrT&&... args)
: bind_(f,std::forward<ConstrT>(args)...)
{ }
void act()
{ bind_(); }
private:
bind_type bind_;
};
int main()
{
Action<int,int> add([](int x, int y)
{ std::cout << (x+y) << std::endl; },
3, 4);
add.act();
return 0;
}
Notice that std::bind is a function and you need to store, as data member, the result of calling it. The data type of that result is not easy to predict (the Standard does not even specify it precisely), so I use a combination of decltype and std::declval to compute that data type at compile time. See the definition of Action::bind_type above.
Also notice how I used universal references in the templated constructor. This ensures that you can pass arguments that do not match the class template parameters T... exactly (e.g. you can use rvalue references to some of the T and you will get them forwarded as-is to the bind call.)
Final note: If you want to store arguments as references (so that the function you pass can modify, rather than merely use, them), you need to use std::ref to wrap them in reference objects. Merely passing a T & will create a copy of the value, not a reference.
Operational code on Coliru
This question was from C++11 days. But for those finding it in search results now, some updates:
A std::tuple member is still the straightforward way to store arguments generally. (A std::bind solution similar to #jogojapan's will also work if you just want to call a specific function, but not if you want to access the arguments in other ways, or pass the arguments to more than one function, etc.)
In C++14 and later, std::make_index_sequence<N> or std::index_sequence_for<Pack...> can replace the helper::gen_seq<N> tool seen in 0x499602D2's solution:
#include <utility>
template <typename... Ts>
class Action
{
// ...
template <typename... Args, std::size_t... Is>
void func(std::tuple<Args...>& tup, std::index_sequence<Is...>)
{
f(std::get<Is>(tup)...);
}
template <typename... Args>
void func(std::tuple<Args...>& tup)
{
func(tup, std::index_sequence_for<Args...>{});
}
// ...
};
In C++17 and later, std::apply can be used to take care of unpacking the tuple:
template <typename... Ts>
class Action
{
// ...
void act() {
std::apply(f, args);
}
};
Here's a full C++17 program showing the simplified implementation. I also updated make_action to avoid reference types in the tuple, which was always bad for rvalue arguments and fairly risky for lvalue arguments.
I think you have an XY problem. Why go to all the trouble to store the parameter pack when you could just use a lambda at the callsite? i.e.,
#include <functional>
#include <iostream>
typedef std::function<void()> Action;
void callback(int n, const char* s) {
std::cout << s << ": " << n << '\n';
}
int main() {
Action a{[]{callback(13, "foo");}};
a();
}

C++11: Calculating variadic function parameter types

Let's say you want to write a function which gets passed an opaque handle to a function of unknown type (say, the name of a struct containing a function with an agreed-upon name), and forwards arguments to that function.
In the non-variadic case, considering single-parameter functions for simplicity, there's two ways to do this: you can let the forwarding function take an argument of arbitrary type, and attempt to call the forwardee function with it, and the compiler will complain during template expansion if it turns out to be incompatible; or you can use decltype and assorted other mechanisms to figure out what type of parameter the forwardee function expects, and explicitly require an argument of that type. I don't know if there's any accepted terminology for these, so I'm going to call them "pass through" and "up front".
The pass through method generalizes straightforwardly to functions with an arbitrary number of parameters, but the up front method doesn't.
#include <iostream>
template<typename T, typename Arg>
void pass_through_1(Arg arg)
{
T::f(arg);
}
template<typename T> struct arg_of_1;
template<typename Ret, typename Arg>
struct arg_of_1<Ret (Arg)>
{
typedef Arg type;
};
template<typename T>
void up_front_1(typename arg_of_1<decltype(T::f)>::type arg)
{
T::f(arg);
}
template<typename T, typename... Args>
void pass_through_var(Args... args)
{
T::f(args...);
}
template<typename T> struct args_of_var;
template<typename...> struct type_list;
template<typename Ret, typename... Args>
struct args_of_var<Ret (Args...)>
{
// typedef Args... type; // can't do this
typedef type_list<Args...> type;
};
// template<typename T>
// void up_front_var(typename args_of_var<decltype(T::f)>::type... args) // can't do this
// {
// T::f(args...);
// }
struct test
{
static void f(int x) { std::cout << x*9 << std::endl; }
};
int main(int, char**)
{
pass_through_1<test>(7);
up_front_1<test>(8);
pass_through_var<test>(9);
// up_front_var<test>(10);
return 0;
}
The problem is that parameter packs aren't allowed to be free-standing, only as template arguments, and if you wrap them in an enclosing template, there's no way to unwrap-and-unpack them in place, only by pattern matching.
"Up front" has some advantages like better self-documentation, and better support for type inference (up_front<T> can itself be decltyped). Is there any way to make it work in the variadic case? (You could of course use std::tuple, but that's rather unsatisfying.)
There's nothing like writing down the question to make you realize the answer.
Here's one way:
template<typename T, typename Args = typename args_of_var<decltype(T::f)>::type>
struct up_front_var;
template<typename T, typename... Args>
struct up_front_var<T, type_list<Args...>>
{
static void forward(Args... args)
{
T::f(args...);
}
};
I don't think there's a way to make a top-level function out of this (you run into the original problem again), but that's possibly not too bad.
Would still be happy to see other solutions.
Maybe I'm not understanding the question correctly, but you can always leave out the argument types and let the compiler infer them.
/* declare */
template<typename T, typename... Args>
void up_front_var(Args... args)
{
T::f(std::forward<Args>(args)...); // need std::forward to correctly handle lvalue/rvalue references
}
/* an example */
class Test {
public:
static void f(const char* fmt, int a, int b);
};
void Test::f(const char* fmt, int a, int b)
{
printf(fmt, a, b);
}
int main()
{
up_front_var<Test>("testing %u, %u", 1, 2); // no need to specify arguments here
return 0;
}