Unfamiliar use of "template" [duplicate] - c++

This question already has answers here:
Explicit template instantiation - when is it used?
(4 answers)
Static table generation works with GCC but not clang; is clang bugged?
(1 answer)
Closed 1 year ago.
I was working with code from an answer to this question:
#include <iostream>
#include <string>
using std::cin;
using std::cout;
template<int N, int I=N-1>
class Table : public Table<N, I-1>
{
public:
static const int dummy;
};
template<int N>
class Table<N,0>
{
public:
static int array[N];
static const int dummy;
};
template<int N, int I>
const int Table<N,I>::dummy = Table<N,0>::array[I] = I + 0*Table<N,I-1>::dummy;
template<int N>
int Table<N,0>::array[N];
template<int N>
const int Table<N,0>::dummy = 0;
template class Table<5>; //<-what does this statement do? The program does not work without it.
int main()
{
std::string s;
int *array = Table<5,0>::array;
for(int i = 0; i < 5; i++)
{
cout << array[i] << " ";
}
cout << "\n";
cout << "Press ENTER to exit.\n";
std::getline(cin, s);
}
The line template class Table<5>; just before the start of the main routine is marked off with a comment in the listing and shows a use of the work "template" that I am not familiar with. What is the justification for this line of code?

Related

Conditional compilation (constexpr if) and "ISO C++ forbids zero-size array"

With the following code:
#include <algorithm>
constexpr int DATA_SIZE = 5;
constexpr int A_ARRAY_ALLOWED_SIZE = 5;
constexpr int A_ARRAY_SIZE = std::min(A_ARRAY_ALLOWED_SIZE, DATA_SIZE);
constexpr int B_ARRAY_SIZE = DATA_SIZE - A_ARRAY_ALLOWED_SIZE;
class A {
int a[A_ARRAY_SIZE];
};
class B {
int b[B_ARRAY_SIZE];
};
int main()
{
A a;
if constexpr (B_ARRAY_SIZE)
{
B b;
}
return 0;
}
I'm getting compiler error (with -pedantic flag) which complains that zero-size array is not allowed. In my example the object with the zero size array is never created but looks like it is still an issue.
I was trying to workaround it with usage of std::conditional but even then I ended up with an additional function like:
constexpr int Get_B_ARRAY_SIZE()
{
if (B_ARRAY_SIZE)
return B_ARRAY_SIZE;
return 1; // workaround for zero-size array
}
What is a proper way of handling such an issue?
EDIT:
I'm aware that all of if branches should contain valid code. I'm also aware that zero-size arrays are not allowed. My question is how to refactor this code to get similar behawior like when compiling without -pedantic flag. I suspect that I can use template meta programming to achieve this purpose but I'm not sure how to do it.
If you need equivalent of std::conditional, but for values, rather than types, you can do it like this:
#include <iostream>
#include <type_traits>
template<size_t N>
struct safe_array_size : std::integral_constant<size_t, N> {};
template<>
struct safe_array_size<0> : std::integral_constant<size_t, 1> {};
int main()
{
char a[safe_array_size<0>::value];
char b[safe_array_size<1>::value];
std::cout << sizeof(a) << std::endl;
std::cout << sizeof(b) << std::endl;
}
Or using std::conditional:
#include <iostream>
#include <type_traits>
template<size_t N>
constexpr size_t safe_array_size = std::conditional_t<N==0, std::integral_constant<size_t, 1>, std::integral_constant<size_t, N>>::value;
int main()
{
char a[safe_array_size<0>];
char b[safe_array_size<1>];
std::cout << sizeof(a) << std::endl;
std::cout << sizeof(b) << std::endl;
}
if constexpr (at least, how you are using it) cannot directly work around this error because it is the class definition that is ill-formed. Whether or not you instantiate the class is irrelevant. You can fix this by ensuring that the array size is never zero with std::max:
#include <algorithm>
constexpr int DATA_SIZE = 5;
constexpr int A_ARRAY_ALLOWED_SIZE = 5;
constexpr int A_ARRAY_SIZE = std::min(A_ARRAY_ALLOWED_SIZE, DATA_SIZE);
constexpr int B_ARRAY_SIZE = DATA_SIZE - A_ARRAY_ALLOWED_SIZE;
class A {
int a[A_ARRAY_SIZE];
};
class B {
int b[std::max(B_ARRAY_SIZE, 1)];
};
int main()
{
A a;
if constexpr (B_ARRAY_SIZE)
{
B b;
}
return 0;
}
Note that std::max is constexpr as of C++14. You could implement your own max function if you are on C++11.
If you need to ensure that the class is never actually instantiated unless the array size is non-zero, the if constexpr check in the above code will handle that.

C++ non-generic class in template

I would like to know how to make a template with an own class:
#include <iostream>
using namespace std;
template<C cc> void A()
{
cout << cc.l << endl;
}
int main()
{
C cc;
A<cc>();
}
class C
{
public:
int l = 10;
};
But it doesn't work, so how to use that class, like a non-generic class parameter, like here:
#include <iostream>
using namespace std;
template<int i> void A()
{
cout << i << endl;
}
int main()
{
A<100>();
}
You can do it as shown below with C++20(&onwards):
//moved definition of C before defining function template `A`
struct C
{
int l = 10;
};
template<C cc> void A()
{
cout << cc.l << endl;
}
int main()
{
//--vvvvvvvvv--------->constexpr added here
constexpr C cc;
A<cc>();
}
Working demo
Two changes have been made:
As template arguments must be compile time constant, constexpr is used.
The definition of C is moved before the definition of function template.

Why values of array cannot be printed using foreach loop in called function when array is passed as argument in caller function? [duplicate]

This question already has answers here:
Range based for-loop on array passed to non-main function
(3 answers)
Closed 3 years ago.
I am trying to print values of array in called function using foreach loop but facing compilation error. Using c++11 compiler in linux platform and using VIM editor.
Tried using C-style for loop and it worked, when the size is passed from calling function
#include <iostream>
using namespace std;
void call(int [], int);
int main()
{
int arr[] = {1,2,3,4,5};
int size = sizeof(arr)/sizeof(arr[0]);
call(arr,size);
}
void call(int a[],int size)
{
for(int i =0 ; i<size; i++)
cout << a[i];
}
For-each loop used in the below code, which fails to compile.
#include <iostream>
using namespace std;
void call(int []);
int main()
{
int arr[] = {1,2,3,4,5};
call(arr);
}
void call(int a[])
{
for ( int x : a )
cout << x << endl;
}
For-each loop in C++11 expects to know the size of array to iterate ? If so, how it will be helpful with respect to traditional for loop. Or something wrong i coded here?
I would look forward for your help. Thanks in advance.
Because int a[] as function parameter is not an array, it is the same as writing int *a.
You can pass the array by reference to make it work:
template <size_t N> void call(int (&a)[N])
working example: https://ideone.com/ZlEMHC
template <size_t N> void call(int (&a)[N])
{
for ( int x : a )
cout << x << endl;
}
int main()
{
int arr[] = {1,2,3,4,5};
call(arr);
}

How to get the length of a int array(method paramater) inside a method? [duplicate]

This question already has answers here:
When a function has a specific-size array parameter, why is it replaced with a pointer?
(3 answers)
Closed 8 years ago.
My code is quite simple:
#include <iostream>
using namespace std;
int test(int b[]){
cout<<sizeof(b)<<endl;
return 1;
}
int main(){
int a[] ={1,2,3};
cout<<sizeof(a)<<endl;
test(a);
system("pause");
}
output of this code is:
12
4
which means that when a[] is transfered as a parameter to function test(),is has been deteriorated as a int *, so the output of size(b) is 4 ,instead of 12.So ,my question is , how can I get the actual length of b[] inside function test() ?
You could do this with a function template:
#include <cstddef> // for std::size_t
template<class T, std::size_t N>
constexpr std::size_t size(T (&)[N])
{
return N;
}
then
#include <iostream>
int main()
{
int a[] ={1,2,3};
std::cout << size(a) << std::endl;
}
Note that in C and C++, int test(int b[]) is another way of saying int test(int* b), so there is no array size information inside of the test function. Furthermore, you could use standard library container types which know their size, such as std::array.

Why does my attempt at detecting static members using SFINAE appear not to work?

I've just made a template to detect if a data member of a class is static defined or not. The accessibility of the member isn't what it should be concerned about(Assuming the member is always accessible by the template) in this post. Here is the code with any symbols for testing:
#include <conio.h>
//#include <stdio.h>
#include <iostream>
struct A1
{
int a;
};
struct A2
{
static int a;
};
int A2::a{};
template < class My_Type >
struct TestStatic
{
template < typename raw_ty > static char fTest(...);
template < typename class_ty, typename arg_ty = decltype(class_ty::a) >
static int fTest(int, arg_ty & = class_ty::a);
enum nRes { result = sizeof(fTest<My_Type>(0)) - 1 };
};
int main(void)
{
int i;
i = TestStatic<A1>::result;
std::cout << i << std::endl;
i = TestStatic<A2>::result;
std::cout << i << std::endl;
_getch();
return(0);
}
The question is when it was built with g++ 4.8 the compiling passed but got the result as two '3's rather than one '0' and another '3'. Is there anything wrong?
Your approach is fundamentally flawed, because decltype(T::x) is perfectly valid for non-static members:
#include <iostream>
struct T
{
int x;
};
int main()
{
std::cout << sizeof(decltype(T::x)) << '\n';
}
// Output: 4
You can get what you want with std::is_member_pointer:
If T is pointer to non-static member object or a pointer to non-static member function, provides the member constant value equal true. For any other type, value is false.
#include <iostream>
#include <type_traits>
struct T
{
int x;
};
struct S
{
static int x;
};
int main()
{
std::cout << !std::is_member_pointer<decltype(&T::x)>::value << ' ';
std::cout << !std::is_member_pointer<decltype(&S::x)>::value << '\n';
}
// Output: 0 1
This works because access to members through the :: syntax results in a pointer-to-member only if the member is not-static; it is of course a normal variable access when the member is static.