Passing variable-length 2D array to functions using template - c++

Here is an example of the problem I am having:
#include <stdio.h>
#include <iostream>
template<std::size_t U, std::size_t V>
void func2(int (&twoDArrayA)[U][V], const int shift){
const int length = 1 << shift;
int twoDArrayB[length][length]; //Successful
}
//template<std::size_t A> <-- Tried to solve the problem by adding this
void func1(const int shift){
const int length = 1 << shift;
int twoDArrayA[length][length]; //Failed
func2(twoDArrayA,shift);
}
int main() {
const int shift = 3;
func1(shift);
}
Error message:
error: no matching function for call to 'func2(int [length][length], const int&)'
template argument deduction/substitution failed:
variable-sized array type 'int' is not a valid template argument
I thought it is because of the use of the template before the func2, so I tried to do the same thing on func1. The attempt of making the call to func1 fails instead. Error message:
error: no matching function for call to 'func1(const int&)'
template argument deduction/substitution failed:
couldn't deduce template parameter 'A'
Is there any way I can pass such an argument as twoDArrayA to func2?

func2 is failing to deduce the array size because it isn't known at compile time; length is being decided at runtime based on the argument you pass to func1. For the pass-by-reference to work with template arguments and deduction, you will need to have a 2D array with defined size at compile time, for example, int arr[8][8].
It looks like the code you're working on wants to decide the array size in func1 based on shift and then pass that array to func2. You might consider designing func2 to take an int** and then access it as you would a 2D array, based on the result of 1<<shift:
void func2(int** twoDArrayA, const int shift) {
const int length = 1 << shift;
int last_item = twoDArrayA[length-1][length-1]
}
You might also find some more helpful resources here!

Related

How std::size_t is calculated in the template code for array type

I was reading the book C++ templates - the complete guide, 2nd edition and got the code from that which looks like this:-
template<typename T>
void showVal(const T &arg1, const T &arg2)
{
std::cout << arg1 << arg2;
}
int main() {
showVal("hello", "world1");
return 0;
}
The above code gave me this error:- "error C2782: 'void showVal(const T &,const T &)': template parameter 'T' is ambiguous". This is reasonable because the arguments I am passing are deduced to const char[6] and const char[7]. To fix this, I have made the changes in the function which look like this after the change :-
template<typename T, std::size_t L1, std::size_t L2>
void showVal(const T (&arg1)[L1], const T(& arg2)[L2])
{
std::cout << arg1 << arg2;
}
PS:- I've got this fix from the book
The main confusion underlies in the value of L1 and L2. How compiler knows that it has to pass 6 and 7 to the template parameter L1 and L2. Is there any rule for array type.
The type of "hello" is const char[6], as shown in the error message of your first attempt. The length of the array is 6. As you can see, the length of the array is part of the type of the array. Since the compiler has to know the type, it implicitly also knows the length.
Just like the template type argument T was deduced to be const char based on the type of the expressions passed to the non-template arguments arg1 and arg2 (those types being const char[6] and const char[7]), so too the template non-type arguments L1 and L2 were deduced from those same parameter types.
function template
template<typename T, std::size_t L1, std::size_t L2>
void showVal(const T (&arg1)[L1], const T(& arg2)[L2])
for call showVal("hello", "world1") compiler will make implicit instantiation
showVal(const char (&arg1)[6], const T(& arg2)[7])
and that is the way you can prevent that array decays to pointer, binding reference to array type, you achieve that array size of arguments is known to function definition.
so for call showVal("hello", "world1"), compiler deduced T is char and arguments type are array of char size 6 and 7 respectively.

Error in using template for function

I want to create a function that returns different types of data-types for different input string. I am using templates for it but seems like I am making some mistake.
template<typename S>
S select(string type){
int integer;
float floaty;
char character;
string strings;
if(type=="int")
return integer;
if(type=="char")
return character;
if(type=="float")
return floaty;
if(type=="string")
return strings;
}
it gives this error when I run it will string argument int .
sam.cpp:771:13: error: no matching function for call to ‘select(std::string&)’
select(type);
^
sam.cpp:771:13: note: candidates are:
In file included from /usr/include/x86_64-linux-gnu/sys/types.h:219:0,
from /usr/include/stdlib.h:314,
from Markup.h:12,
from sam.cpp:3:
/usr/include/x86_64-linux-gnu/sys/select.h:106:12: note: int select(int, fd_set*, fd_set*, fd_set*, timeval*)
extern int select (int __nfds, fd_set *__restrict __readfds,
^
/usr/include/x86_64-linux-gnu/sys/select.h:106:12: note: candidate expects 5 arguments, 1 provided
sam.cpp:17:3: note: template<class S> S select(std::string)
S select(string type){
^
sam.cpp:17:3: note: template argument deduction/substitution failed:
sam.cpp:771:13: note: couldn't deduce template parameter ‘S’
select(type);
If it is wrong way and there is a better way of doing things then do share, Thanks.
In C++ template type deduction is based on parameter and not on return type so, in your particular case, when you are calling the function select, you have to explicitly specify the template argument.
then how will I achieve what I want to do with this function?
Use template specialization.
template<typename S>
S select(){
static_assert("Not Implemented");
}
template<> int select<int>() {
int integer;
//To Do
return integer;
}
template<> float select<float >() {
float floaty;
//To Do
return floaty;
}
//Remaining Specialization
and call the respective specialization using explicit template parameter
int main()
{
int _integer = select<int>();
float _float = select<float>();
..........
}
There's no way this can work. Templates require their parameters to be known at compile time, but the value of type is only known at run time.
If S is int then return strings won't compile, but if S is string then return integer won't compile.
And as others have pointed out S cannot be deduced, so you have to specify it explicitly in the call. But it still can't work for the reason above.
(Quite apart from all that, you haven't initialised any of the values.)

Is it possible to legally overload a string literal and const char*?

Is it possible in C++11 to overload const char*'s and string literals (const char[])?
The idea is to avoid having to call strlen to find the string length when this length is known already.
This snippet breaks on G++ 4.8 and Clang++ 3.2:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
template<typename T, int N>
void length(const T(&data)[N]) {
printf("%u[]\n", N - 1);
}
template<typename T>
void length(const T* data) {
printf("*%u\n", (unsigned)strlen(data));
}
int main() {
length("hello");
const char* p = "hello";
length(p);
return 0;
}
Error (Clang):
test2.cpp:16:3: error: call to 'length' is ambiguous
length("hello");
^~~~~~
test2.cpp:6:6: note: candidate function [with T = char, N = 6]
void length(const T(&data)[N]) {
^
test2.cpp:11:6: note: candidate function [with T = char]
void length(const T* data) {
^
1 error generated.
Hacked a bit, and this appears to work:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
template<typename T, int N>
void length(const T(&data)[N]) {
printf("%u[]\n", N - 1);
}
template<typename T>
void length(T&& data) {
printf("*%u\n", (unsigned)strlen(data));
}
const char *foo() {
return "bar";
}
int main() {
length("hello");
const char* p = "hello";
length(p);
length(foo());
return 0;
}
Is this valid C++11? The string literal appears to overload on T&& when the array specialization is removed. What causes this ambigousness to be resolved, but not the one in the first code snippet?
In the first case, during overload resolution you have a perfect match requiring no conversion against an array to pointer conversion (which is in the category "lvalue transformation", along with lvalue to rvalue and function to pointer conversion). A difference that is only made by an lvalue transformation is not sufficient for overload resolution to pick a winner.
In the second case, during overload resolution, both functions have the exact same parameter type. Then partial ordering as the last resort finds that the second template would accept all arguments you ever pass to it, wheras the first template only accepts arrays. Therefor the first template in the second case is found more specialized and taken.
As for your other question - no, overloading specifically for string literals is not possible. You are always going to catch arrays of the same size along with them.

How to pass array to function template with reference

I am learning c++ template concepts. I do not understand the following.
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename T>
T fun(T& x)
{
cout <<" X is "<<x;
cout <<"Type id is "<<typeid(x).name()<<endl;
}
int main ( int argc, char ** argv)
{
int a[100];
fun (a);
}
What i am trying?
1) T fun (T & x)
Here x is a reference, and hence will not decayed 'a' into pointer type,
but while compiling , i am getting the following error.
error: no matching function for call to ‘fun(int [100])’
When I try non-reference, it works fine. As I understand it the array is decayed into pointer type.
C-style arrays are very basic constructs which are not assignable, copyable or referenceable in the way built-ins or user defined types are. To achieve the equivalent of passing an array by reference, you need the following syntax:
// non-const version
template <typename T, size_t N>
void fun( T (&x)[N] ) { ... }
// const version
template <typename T, size_t N>
void fun( const T (&x)[N] ) { ... }
Note that here the size of the array is also a template parameter to allow the function to work will all array sizes, since T[M] and T[N] are not the same type for different M, N. Also note that the function returns void. There is no way of returning an array by value, since the array is not copyable, as already mentioned.
The problem is in the return type: you cannot return an array because arrays are non-copiable. And by the way, you are returning nothing!
Try instead:
template <typename T>
void fun(T& x) // <--- note the void
{
cout <<" X is "<<x;
cout <<"Type id is "<<typeid(x).name()<<endl;
}
And it will work as expected.
NOTE: the original full error message (with gcc 4.8) is actually:
test.cpp: In function ‘int main(int, char**)’:
test.cpp:17:10: error: no matching function for call to ‘fun(int [100])’
fun (a);
^
test.cpp:17:10: note: candidate is:
test.cpp:7:3: note: template<class T> T fun(T&)
T fun(T& x)
^
test.cpp:7:3: note: template argument deduction/substitution failed:
test.cpp: In substitution of ‘template<class T> T fun(T&) [with T = int [100]]’:
test.cpp:17:10: required from here
test.cpp:7:3: error: function returning an array
The most relevant line is the last one.

size_t and unsigned int does not match in a template function's parameter list

I want to use a stack to store indices of an array,so I use the following typedef,where istack is a template class for stack:
typedef istack<size_t> IndexStack;
and I declare a stack by
IndexStack stack;
But when I call the following function (where A.size() returns a size_t);
stack.push_back(A.size());
GCC gives the following error
sort.cpp: In function 'void quicksort2(Array&)':
sort.cpp:50:27: error: no matching function for call to 'istack<unsigned int>::push_back(size_t)'
iarray.h:103:8: note: candidate is: void istack<T>::push_back(T&) [with T = unsigned int]
How can I make it work?
#include <cstddef>
template <class T>
struct istack
{
void push_back(T& value);
std::size_t size() const;
};
int main()
{
typedef istack<size_t> IndexStack;
IndexStack a, stack;
stack.push_back(a.size());
}
This code produces an error
In function 'int main()':
13 no matching function for call to 'istack<unsigned int>::push_back(size_t)'
note 5 candidates are: void istack<T>::push_back(T&) [with T = unsigned int]
Note that it lists candidates. (I suspect you are not reading / posting the entire error message.)
The given candidate doesn't match the call, because the reference is non-const. A temporary (such as the result of a.size()) cannot be bound to a non-const reference.
push_back should be taking a const T& value