C++ template defining number of parameters of function - c++

Lets say i have a class looking like this
template<int n>
class A{
array<size_t, n> sizes;
//...
public:
template <int k>
A<k> reshape(array<size_t, k> new_sizes){
return A<k>(new_sizes):
}
};
it works but the parameter new_sizes is syntatically suboptimal, since i have to call it like that:
foo.reshape(array<size_t, 3>{1,2,3});
This does not work:
foo.reshape({1,2,3});
Is there a way to either define a initializer_list with compile time size (so i could use it instead of the array) OR (even better) a way to define the size of a variadic parameter, so i could write something like
foo.reshape(1,2,3);

OR (even better) a way to define the size of a variadic parameter, so i could write something like
foo.reshape(1,2,3);
You could take the sizeof... a parameter pack:
template <size_t N>
class A {
std::array<size_t, N> sizes;
public:
A() = default;
template <class... Args>
A(Args&&... ss) : sizes{static_cast<size_t>(ss)...} {}
template <class... Args>
A<sizeof...(Args)> reshape(Args&&... new_sizes) {
// ^^^^^^^^^^^^^^^
return A<sizeof...(Args)>(static_cast<size_t>(new_sizes)...);
}
};
// deduction guide:
template <class... Args>
A(Args&&...) -> A<sizeof...(Args)>;
Demo

{1, 2, 3} has no type but can be deduced as initializer_list<T> or T[N]
So to keep your syntax, it would be:
template <std::size_t K>
A<K> reshape(/*const*/ size_t (&new_sizes)[K])
{
return A<K>(new_sizes):
}
so i could write something like foo.reshape(1,2,3);
For that variadic template:
template <typename... Ts>
A<sizeof...Ts> reshape(Ts... elems)
{
return reshape({elems...}); // using above method
}

Related

Is there a way to get a given number of inputs where the number is given by a template in compile time in c++?

For example, suppose I make a class like below:
template <unsigned int INPUT_SIZE>
class A{
public:
int operator()(int input, ...){ // get INPUT_SIZE-many inputs
// return sum;
}
};
I want to get input as many as INPUT_SIZE, not more or less. How can I achieve that?
Also, I am using c++11, but if there is a better way in c++14 or above, I would also like to know.
Live demo 1
template <class T, auto> using always_t = T;
template <class T, class Arity>
struct A_impl;
template <class T, std::size_t... Is>
struct A_impl<T, std::index_sequence<Is...>>
{
int operator ()(always_t<T, Is>...)
{
return 0;
}
};
template <std::size_t N>
struct A : A_impl<int, std::make_index_sequence<N>>
{ };
A<2>{}(1, 2); // fine
A<2>{}(1, 2, 3); // fail
and this is a version that allows you to compute the sum of the parameters:
Live demo 2
template <class T, auto> using always_t = T;
template <class T, class Arity>
struct A_impl;
template <class T, std::size_t... Is>
struct A_impl<T, std::index_sequence<Is...>>
{
constexpr int operator ()(std::tuple<always_t<T, Is>...>&& t) {
auto adder = [](auto... ts) {
return (0 + ... + ts);
};
return std::apply(adder, std::move(t));
}
};
template <std::size_t N>
struct A : A_impl<int, std::make_index_sequence<N>>{
};
constexpr int sum = A<3>{}({1, 4, 5});
static_assert(sum == 10);
The trick is to use a parameter pack with length N so that we can use it to expand as N times a specific type into the parameter list of A_impl::operator().
A parameter pack can expand into N repetition of the pattern that (usually) precede ...
Consider a function like:
template<class... T>
void foo(T...);
T... indicate in simple terms that it can be replaced by successive types into the parameter list of foo, one possible expansion could be foo(int, int, double, char), also notice that what preside ... is an identifier that comes from class... T.
Returning to the code, we need to generate a parameter pack, we did that through std::make_index_sequence<N>, that generate the sequence 0..(N-1) which is captured by std::size_t... Is, then we use this pack to expand the pattern always_t<T, Is> that is just an alias to T=int, this end up repeating T=int as many times as elements Is contains.
Note: ellipsis parameter ... is not the same as parameter pack.

function return type with a different template parameter

I have some C++ classes that all have the same template parameters
template <typename T, size_t i>
struct A {
};
template <typename T, size_t i>
struct B : A<T,i>{
};
template <typename T, size_t i>
struct C : A<T,i>{
};
and so on. I also have a series of methods that will work on any of these classes. However, the problem is in the return type. I would like this method to return an instance of the passed in class, with the integer decremented by one. For instance, if I just overload the function, that would look like this
template <typename T, size_t i>
A<T,i-1> func(const A<T,i> & a){
}
template <typename T, size_t i>
B<T,i-1> func(const B<T,i> & a){
}
template <typename T, size_t i>
C<T,i-1> func(const C<T,i> & a){
}
Is there a way to accomplish this without overloading the function for each type? By that I mean... is it possible to replace these with a single templated function? The logic is identical for all of the functions.
I imagine that that would look something like
template <typename P, size_t i>
P<i-1> func( const P<i> & p ){
}
where P somehow captures the original type A, B, or C, as well as the inner type T.
Or, if you think CRTP is the way to go, then how would I structure that?
It sounds like you need to use a template template parameter. These template parameters are themselves class templates. In the following example, P is a template parameter which expects a class template where that class template expects a type argument followed by a size_t argument (such as the class templates A, B or C you provided):
template<template<class, size_t> class P, class T, size_t i>
P<T, i - 1> my_func(const P<T, i> & my_P);
int main()
{
A<int, 10> a;
B<char, 3> b;
C<double, 7> c;
auto smaller_a = my_func(a); // is a A<int, 9>
auto smaller_b = my_func(b); // is a B<char, 2>
auto smaller_c = my_func(c); // is a C<double, 6>
}
Since you did not explain what your function should actually do, I've just provided the function declaration and left out the definition.
C++11 compilation demonstration : https://godbolt.org/g/zpXVEb
I don't normally use the template template syntax.
In case template type definitions are recursive, I'd rather stick with the old school way:
template<typename T, int I>
struct A{
using Other=A<T,I-1>;
};
template<typename P>
typename P::Other f(P);

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

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.

Create a sequence of explicit function template instantiations

In C++ 11, can I build a template which explicitly instantiates a sequence of function templates into an array initialiser? What I want to achieve (please don't ask why I need that, because it's a long story) looks like
// The template I want to instantiate:
template<size_t N> void callbackTemplate(const int dummy) {
// Do something which needs to know 'N'.
}
// The variable I want to assign 'callbackTemplate' instantiations to:
void (*callback)(const int dummy); // This cannot be std::function, because it
// is not defined by me! It is already there and
// must be used as it is.
// This is the set of instantiations I want to prepare:
std::array<decltype(callback), 3> callbackTemplates = {
callbackTemplate<0>, callbackTemplate<1>, callbackTemplate<2>
};
The code above works as it is. What I want to change is the initialisation of the callbackTemplates array. I want the initialiser to become a template which is dependent on a compile-time constant and creates the instantiations 0..N.
The problem is somehow related to C++ static const array initialization in template class, but I did not manage to "templatise" the instantiation of the other template.
You can do this using an implementation of C++14's std::integer_sequence. Here's one.
With callback_t defined as
using callback_t = decltype (callback);
you can just pass a sequence and make use of the type deduction:
template<unsigned... Is>
array<callback_t, sizeof...(Is)> make_callback_array_impl(seq<Is...>)
{
return { callbackTemplate<Is>... };
}
template<unsigned N>
array<callback_t, N> make_callback_array()
{
return make_callback_array_impl(GenSeq<N>{});
}
live demo
This can be done with variable template specializations.
template<class>
int callbackTemplates_v;
template<std::size_t... Indicies>
std::array<decltype(callback), sizeof...(Indicies)>
callbackTemplates_v<std::index_sequence<Indicies...>> = {callbackTemplate<Indicies>...};
template<std::size_t N>
auto callbackTemplates = callbackTemplates_v<std::make_index_sequence<N>>;
Now callbackTemplates<N> is an array of N instaniations of callbackTemplate from 0..N-1.
Do you mean something as follows?
template <std::size_t ...>
struct range
{ };
template <std::size_t N, std::size_t ... Next>
struct rangeH
{ using type = typename rangeH<N-1U, N-1U, Next ... >::type; };
template <std::size_t ... Next >
struct rangeH<0U, Next ... >
{ using type = range<Next ... >; };
template <std::size_t N>
struct arrayWrapper
{
private:
std::array<decltype(callback), N> callBT;
template <std::size_t ... rng>
arrayWrapper (const range<rng...> &)
: callBT{ callbackTemplate<rng>... }
{ }
public:
arrayWrapper ()
: arrayWrapper (typename rangeH<N>::type())
{ }
};
If you can use C++14, you can throw away rangeH and range and the wrapper become simply
template <std::size_t N>
struct arrayWrapper
{
private:
std::array<decltype(callback), N> callBT;
template <std::size_t ... rng>
arrayWrapper (const std::index_sequence<rng...> &)
: callBT{ callbackTemplate<rng>... }
{ }
public:
arrayWrapper ()
: arrayWrapper (std::make_index_sequence<N>())
{ }
};