Partial template specialization using STL - c++

I have a function which has template class object as parameter. Its working fine with user defined template class object as paramerter but its giving arror with std::array object. If I am trying to execute this program
#include<iostream>
#include<array>
template<typename T1, int size>
void print(std::array<T1, size> &arr)
{
for (auto ele : arr)
std::cout << ele << " ";
}
template<int size>
void print(std::array<float, size> &arr)
{
std::cout << "its float" << std::endl;
for (auto ele : arr)
std::cout << ele << " ";
}
int main()
{
std::array<int, 3> arr{1,3,4};
std::array<float, 2> ar2{1.3, 3.4};
print(arr);
print(ar2);
return 0;
}
And getting this error
error: no matching function for call to ‘print(std::array<int, 3>&)’
print(arr);
But when I am running this program then its working fine.
#include<iostream>
#include<array>
template<class T, int size>
class Template
{
public:
std::array<T, size> arr;
};
template<typename T1, int size>
void print(Template<T1, size> &obj)
{
for (auto ele : obj.arr)
std::cout << ele << " ";
}
template<int size>
void print(Template<float, size> &obj)
{
for (auto ele : obj.arr)
std::cout << ele << " ";
}
int main()
{
Template<int, 3> array;
array.arr[0] = 1;
array.arr[1] = 2;
array.arr[2] = 3;
Template<float, 2> arr2;
arr2.arr[0] = 2.3;
arr2.arr[1] = 2.9;
print(array);
print(arr2);
return 0;
}
I don't understand why std::array<T1, size> is not suitable match for std::array<int, 3> but class Template<T1,size> is suitable match for Template<int, 3>

Because the 2nd template parameter's type of std::array is std::size_t, but not int; they don't match and cause template argument deduction on the non-type template parameter fails.
(emphasis mine)
If a non-type template parameter is used in the parameter list, and the corresponding template argument is deduced, the type of the deduced template argument ( as specified in its enclosing template parameter list, meaning references are preserved) must match the type of the non-type template parameter exactly, except that cv-qualifiers are dropped, and except where the template argument is deduced from an array bound—in that case any integral type is allowed, even bool though it would always become true:
Change the type to std::size_t.
template<typename T1, std::size_t size>
void print(std::array<T1, size> &arr)
{
for (auto ele : arr)
std::cout << ele << " ";
}
template<std::size_t size>
void print(std::array<float, size> &arr)
{
std::cout << "its float" << std::endl;
for (auto ele : arr)
std::cout << ele << " ";
}
LIVE

You were close. Use size_t instead of int. This compiles:
#include <iostream>
#include <array>
template<typename T1, size_t size>
void print(std::array<T1, size> const &arr)
{
for (auto ele : arr)
std::cout << ele << " ";
}
template<size_t size>
void print(std::array<float, size> &arr)
{
std::cout << "its float" << std::endl;
for (auto ele : arr)
std::cout << ele << " ";
}
int main()
{
std::array<int, 3> arr{1,3,4};
std::array<float, 2> ar2{1.3, 3.4};
print(arr);
print(ar2);
return 0;
}

Related

get total number of elements in a multidimensional array using std::extent

How to find total number of elements in a multidimensional array using std::extent. This is my sample code:
#include <iostream>
#include <type_traits>
int main()
{
int32_t int_arr[10][100][1000];
int32_t no_of_elements = 1;
// compiler error in below for loop block
for (int32_t i = 0; i < std::rank<decltype(int_arr)>{}; ++i)
no_of_elements *= std::extent<decltype(int_arr), i>{};
no_of_elements *= std::extent<decltype(int_arr), 0>{};
no_of_elements *= std::extent<decltype(int_arr), 1>{};
no_of_elements *= std::extent<decltype(int_arr), 2>{};
std::cout << no_of_elements << std::endl;
std::cout << sizeof(int_arr) / sizeof(std::remove_all_extents<decltype(int_arr)>::type) << std::endl;
return 0;
}
error: the value of ‘i’ is not usable in a constant expression 9 | no_of_elements *= std::extent<decltype(int_arr), i>{};
With C++14 std::index_sequence, you can use std::extent with something like:
template <typename T, std::size_t... Is>
constexpr std::size_t count_elements(std::index_sequence<Is...>)
{
return (1 * ... * std::extent<T, Is>{}); // C++17 fold expression
// Alternatives exist for C++11/C++14
}
template <typename T>
constexpr std::size_t count_elements()
{
return count_elements<T>(std::make_index_sequence<std::rank<T>{}>());
}
int main()
{
int32_t int_arr[10][100][1000];
int32_t no_of_elements = count_element<decltype(int_arr)>();
std::cout << no_of_elements << std::endl;
}
Much simpler way is to get the type of array element and then sizeof(array)/sizeof(element) is an answer:
int32_t int_arr[10][100][1000];
using element = std::remove_all_extents<decltype(int_arr)>::type;
no_of_elements = sizeof(int_arr)/sizeof(element);
So use remove_all_extents
in templated version (like in C++14 variable template):
template <typename ArrayType>
constexpr std::size_t no_of_elements_v =
sizeof(ArrayType) / sizeof(remove_all_extents_t<ArrayType>;
If you really insist on using C++11 and std::extent - this is the solution:
template <typename T, std::size_t rank = std::rank<T>{}, std::size_t dim = 0>
struct NumOfElements :
std::integral_constant<std::size_t, std::extent<T, dim>{} * NumOfElements<T, rank, dim + 1>::value>
{};
template <typename T, std::size_t rank>
struct NumOfElements<T, rank, rank> :
std::integral_constant<std::size_t, 1u>
{};
And use NumOfElements<decltype(int_arr)>::value
But much, much simpler is this simple template version w/o any type_traits, if you replace integral_constant with simple static member variable - it should work even in pre-C++11:
template <typename T>
struct NumOfElements : std::integral_constant<std::size_t, 1u>
{};
template <typename T, std::size_t N>
struct NumOfElements<T[N]> : std::integral_constant<std::size_t,
N * NumOfElements<T>::value>
{};
#include <iostream>
#include <type_traits>
#include <typeinfo>
template<class A>
size_t getSize(const A&)
{
typedef typename std::remove_all_extents<A>::type Type;
return sizeof(A) / sizeof(Type);
}
int main()
{
int a1[3][10];
float a2[5][10][10];
double a3[3][10];
std::int32_t int_arr[10][100][1000];
std::cout << "Size of array a1: " << getSize(a1) << std::endl;
std::cout << "Size of array a2: " << getSize(a2) << std::endl;
std::cout << "Size of array a3: " << getSize(a3) << std::endl;
std::cout << "Size of array int_arr: " << getSize(int_arr) << std::endl;
}
Output:
Size of array a1: 30
Size of array a2: 500
Size of array a3: 30
Size of array int_arr: 1000000
One minus of this code is function getSize() is generated for each type of array:
type of a1: int[3][10] (GCC outputs: A3_A10_i)
type of a2: float[5][10][10] (GCC outputs: A5_A10_A10_f)
type of a3: double[3][10] (GCC outputs: A3_A10_d)
I don't think std::extent is the right choice here. I'd simply define a "recursive" template:
template<typename T>
struct nested_array_size
{
static constexpr size_t value = 1;
};
template<typename T, size_t N>
struct nested_array_size<T[N]>
{
static constexpr size_t value = N * nested_array_size<T>::value;
};
std::cout << nested_array_size<double[1][2][3][4]>::value << std::endl;
std::cout << nested_array_size<int[5]>::value << std::endl;
std::cout << nested_array_size<int[5][6]>::value << std::endl;

Function that can take arrays with different dimensions

Is there a method to create a single function that can take any dimension of vector without overloading?
Currently I have,
someFunction(vector<int> a)
someFunction(vector<vector<int> > a)
someFunction(vector<vector<vector<int> > > a)
However, would it be possible to have a function:
singleFunction(<n-dimension vector>)
{
// Get dimension of array/vector
}
You can use a recursive template function
#include <iostream>
#include <vector>
void func(int el) {
std::cout << el << std::endl;
}
template<typename T>
void func(std::vector<T> v) {
for (const T& el : v) {
func(el);
}
}
int main() {
std::vector<std::vector<int>> v {{1, 2}, {2, 3}};
func(v);
return 0;
}
It's calling it itself for each element until it reaches elements of type int.
To get the dimension you can use the same pattern:
#include <iostream>
#include <vector>
template<typename T>
int someFunction(std::vector<T> v, int dim = 1);
template<>
int someFunction(std::vector<int> v, int dim) {
return dim;
}
template<typename T>
int someFunction(std::vector<T> v, int dim) {
return someFunction(T(), dim + 1);
}
template<typename T>
void singleFunction(std::vector<T> v) {
int dim(someFunction(v));
std::cout << dim << std::endl;
// Do something
}
int main() {
std::vector<std::vector<std::vector<int>>> v {{{1, 0}, {2, 4}}, {{2, 2}, {3, 0}}};
singleFunction(v);
singleFunction(std::vector<std::vector<int>>());
singleFunction(std::vector<int>());
return 0;
}
Here it creates a new object of value type and calls itself until its value type is int. Every time it increments the dimension.
Perhaps you could try this approach, I think this is exactly what you are asking (adopted from std::rank):
#include <iostream>
#include <vector>
#include <type_traits>
template<typename T>
struct vector_rank : public std::integral_constant<std::size_t, 0> {};
template<typename T>
struct vector_rank<std::vector<T>> : public std::integral_constant<std::size_t, vector_rank<T>::value + 1> {};
template<typename T>
size_t GetVectorRank(T)
{
return vector_rank<T>::value;
}
int main()
{
std::vector<std::vector<std::vector<std::vector<std::vector<int>>>>> v1;
std::cout << GetVectorRank(v1) << std::endl;
std::vector<std::vector<std::vector<int>>> v2;
std::cout << GetVectorRank(v2) << std::endl;
return 0;
}
The second template be selected recursively while the type is std::vector<T>, the first template will be selected for everything else as well as at the end of recursion. The above example will return:
5
3
Demo: https://ideone.com/CLucGA
With C++17 you can write a pretty simple solution:
template<typename T >
constexpr int func(){
if constexpr (is_vector<typename T::value_type>::value )
return 1+func<typename T::value_type>();
return 1;
}
int main() {
cout<< func<vector<vector<vector<vector<vector<int>>>>>>() <<endl;
return 0;
}
which return 5 as expected.
You need to define is_vector as follows:
template<class T>
struct is_vector{
static bool const value = false;
};
template<class T>
struct is_vector<std::vector<T> > {
static bool const value = true;
};
A simple template should solve this. From memory:
template <T> singleFunction(vector<T> &t) {
return t.size();
}
you can get the dimension with this code
#include <vector>
#include <iostream>
template<unsigned N, typename T>
struct meta {
static unsigned func() {//terminale recursion case
return N;
}
};
template<unsigned N, typename T>
struct meta<N, std::vector<T> > {//mid recursion case
static unsigned func() {
return meta<N + 1, T>::func();
}
};
template<typename T>
unsigned func(T) { //adapter to deduce the type
return meta<0, T>::func();
}
int main() {
std::cout << func(std::vector<std::vector<std::vector<int> > >()) << std::endl;
std::cout << func(std::vector<int>()) << std::endl;
std::cout << func(int()) << std::endl;
std::cout << func(std::vector<std::vector<std::vector<std::vector<std::vector<std::vector<int> > > > > >()) << std::endl;
return 0;
}
will output
3
1
0
6

How to initialize template member array from constructor parameter?

Essentially I want a template class with an array whose size is a template parameter, to hold constant content.
Something like:
template<size_t S> struct Foo {
const int bar[S];
Foo(const int(&par)[S]) : bar(par) {
cout << "bar size is " << S << endl;
}
};
auto foo = Foo({1,2,3});
I have been searching and tinkering a bit, and almost have a workaround implemented with an intermediate static method and using std::array:
template<size_t S> struct Baz {
const array<int,S> qux;
Baz(const array<int,S>&par) : qux(par) {
cout << "size is " << S << endl;
}
};
template<size_t S> Baz<S>
GetBaz(const array<int,S>&in) {
return Baz<S>(in);
}
int main() {
auto sample = GetBaz({1,2,3});
return 0;
}
... Which is already quite some boilerplate, but still the std::array does not seem to get constructed from an initialiser list? :-(
prog.cpp: In function 'int main()':
prog.cpp:27:30: error: no matching function for call to 'GetBaz(<brace-enclosed initializer list>)'
auto sample = GetBaz({1,2,3});
Post-DR1591 built-in array bound are now deducible from a braced-init-list, so:
template<size_t S> struct Baz {
const array<int,S> qux;
Baz(const array<int,S>&par) : qux(par) {
cout << "size is " << S << endl;
}
Baz(const int (&par)[S]) : qux(std::experimental::to_array(par)) {}
};
template<size_t S> Baz<S>
GetBaz(const int (&in)[S]) {
return Baz<S>(in);
}
std::experimental::to_array creates an std::array from a built-in one. See the linked cppreference page for implementation.
You can go built-in arrays all the way, but it's somewhat more annoying:
template<size_t S> struct Baz {
const int bar[S];
template<size_t... Is>
Baz(const int (&par)[S], std::index_sequence<Is...>)
: bar { par[Is]... } {}
Baz(const int (&par)[S]) : Baz(par, std::make_index_sequence<S>()) {}
};
template<size_t S> Baz<S>
GetBaz(const int (&in)[S]) {
return Baz<S>(in);
}
Not sure if I fully understood the questions. Is that what you are trying to achieve?
#include <iostream>
#include <array>
template<size_t S> struct Baz {
const std::array<int,S> qux;
Baz(const std::array<int,S>& par) : qux(par) {
std::cout << "size is " << qux.size() << std::endl;
}
};
int main() {
auto sample = Baz<5>({1,2,3}); // size = 5, values = 1, 2, 3, 0, 0
return 0;
}
Summary:
Use an std::array instead of a raw array.
Specify the template argument, eg: Baz<5>(...).
Class template arguments are not deduced.
You can do it with a classic C array, but using a variadic constructor
#include <array>
#include <cstddef>
#include <iostream>
using namespace std;
template <size_t S> struct Foo {
const int bar[S];
const std::array<int, S> bar2;
template <typename ... I>
Foo (const I & ... i) : bar {i...}, bar2 {{i...}}
{
cout << "bar size is " << S << " == " <<
(sizeof(bar)/sizeof(bar[0])) << " == " << bar2.size() << endl;
}
};
int main()
{
Foo<3> foo {1,2,3};
auto foo2 = Foo<4>{1,2,3,4};
return 0;
}

Syntax help. Template operator() in template function object

What is the proper syntax I need to run what I'm trying to run in main() below?
#include <iostream>
#include <vector>
template <int... Is>
void foo() {
std::vector<int> v{Is...};
for (int x : v) std::cout << x << ' ';
}
template <int... Is>
struct Foo {
template <typename T, typename... Ts>
void operator()() const {
std::cout << sizeof(T) << ' ' << sizeof...(Ts) << '\n';
foo<Is...>();
}
};
int main() {
// Foo<0,1,2>()<bool, char, long>();
Foo<0,1,2> f;
f<bool, char, long>(); // Won't compile
}
I don't think you can manually specify template arguments for operator overloads. However, you can write
f.operator()<bool, char, long>();

Variadic template pack expansion argument id

I am trying to make a variadic template function that reads elements in order (with an index). The goal is, for example to call the function read_tuple to read two ints with id 0 and 1 (with read_int(0) and read_int(1)).
Here is the code I get so far:
int data[] = {10,20,30,40};
int int_read(int id)
{
return data[id];
}
template <typename T>
T read(int& index)
{
index--;
int value = int_read(index);
std::cout << "index :" << index << " value: " << value << std::endl;
return value;
}
template <typename... Args>
std::tuple<Args...> read_tuple()
{
int index = sizeof...(Args);
return std::tuple<Args...>(read<Args>(index)...);
}
I can call it like that:
auto tuple = read_tuple<int, int>();
std::cout << "First: " << std::get<0>(tuple) << std::endl;
And I get the following output:
index :1 value: 20
index :0 value: 10
First: 10
However, this code is dependent of the order of evaluation of the read function. How can I generate an index dependent of the pack expansion (to avoid undefined behavior)?
As Piotr pointed out, the order of evaluation is garanteed if you use braced-init-list. Be carefull though if you use GCC prior to 4.9.1 as it does not work (c.f. Evaluation order (sequenced-before relation) among initializer-clauses in braced-init-list).
If you use a version that does not garantee the order of initialization (or just want to generate ids) you can use an indexer (from other stackoverflow post):
template<int... I> struct index {
template<int n> using append = index<I..., n>;
};
template<int N> struct make_index {
typedef typename make_index<N - 1>::type::template append<N - 1> type;
};
template<> struct make_index<0> { typedef index<> type; };
template<int N> using indexer = typename make_index<N>::type;
You can use it like that:
int data[] = {10,20,30,40};
int int_read(int id)
{
return data[id];
}
template <typename T>
T read(int index)
{
int value = int_read(index);
std::cout << "index :" << index << " value: " << value << std::endl;
return value;
}
template <typename... Args, int... i>
std::tuple<Args...> read_tuple_indexed(index<i...>)
{
return std::tuple<Args...>(read<Args>(i)...);
}
template <typename... Args>
std::tuple<Args...> read_tuple()
{
return read_tuple_indexed<Args...>(indexer<(sizeof...(Args))>());
}