I wrote a c++ program as fllow(3.43.cpp):
#include <iostream>
using std::cout;
using std::endl;
void version_1(int **arr) {
for (const int (&p)[4] : arr) {
for (int q : p) {
cout << q << " ";
}
cout << endl;
}
}
int main() {
int arr[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
version_1(arr);
return 0;
}
Then I compile it by using: gcc my.cpp -std=c++11, there is an error I can not deal with.
Info:
3.43.cpp:6:30: error: no matching function for call to ‘begin(int**&)’
for (const int (&p)[4] : arr) {
^
3.43.cpp:6:30: note: candidates are:
In file included from /usr/include/c++/4.8.2/bits/basic_string.h:42:0,
from /usr/include/c++/4.8.2/string:52,
from /usr/include/c++/4.8.2/bits/locale_classes.h:40,
from /usr/include/c++/4.8.2/bits/ios_base.h:41,
from /usr/include/c++/4.8.2/ios:42,
from /usr/include/c++/4.8.2/ostream:38,
from /usr/include/c++/4.8.2/iostream:39,
from 3.43.cpp:1:
/usr/include/c++/4.8.2/initializer_list:89:5: note: template<class _Tp> constexpr const _Tp* std::begin(std::initializer_list<_Tp>)
begin(initializer_list<_Tp> __ils) noexcept
I search it in google, but not find similar answer.
Since arr is just a pointer, there's no way to deduce how big it is. But, since you are actually passing in a real array, you can just template your function on its dimensions so you take the actual array by reference rather than having it decay to a pointer:
template <size_t X, size_t Y>
void foo(const int (&arr)[X][Y])
{
std::cout << "Dimensions are: " << X << "x" << Y << std::endl;
for (const int (&row)[Y] : arr) {
for (int val : row) {
std::cout << val << ' ';
}
std::cout << std::endl;
}
}
int main() {
int arr[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
foo(arr);
}
std::begin() and std::end() won't work for pointers. They only work for arrays. If you want to deduce the size of your array you'll need to pass it as a reference your function:
#include <cstddef>
template <std::size_t A, std::size_t B>
void version_1(int (&arr)[B][A]) {
for (const int (&p)[A] : arr) {
for (int q : p) {
cout << q << " ";
}
cout << '\n';
}
}
Pointers are not the same as arrays. To be able to use range based for, your container must support std::begin and std::end. Standard C arrays can be used, but not pointers.
Related
#include <iostream>
#include <vector>
#include <string>
#include <type_traits>
#include <map>
#include <any>
using namespace std;
int func1(int a, int b, int c) {
return a + b + c;
}
int func1Wrapper(map<string, std::any> params)
{
int a = any_cast<int>(params["a"]), b = any_cast<int>(params["b"]), c = any_cast<int>(params["c"]);
return func1(a,b,c);
}
double func2(int a, int b) {
return a * b;
}
double func2Wrapper(map<string, std::any> params)
{
int a = any_cast<int>(params["a"]), b = any_cast<int>(params["b"]);
return func2(a,b);
}
int func3(int a, string b) {
return a + b.length();
}
int func3Wrapper(map<string, std::any> params)
{
int a = any_cast<int>(params["a"]);
string b = any_cast<string>(params["b"]);
return func3(a,b);
}
int func4(int a, vector<int> b) {
int sum = 0;
for (const auto& x : b) sum += x;
return a + sum;
}
int func4Wrapper(map<string, std::any> params)
{
int a = any_cast<int>(params["a"]);
auto b = any_cast<vector<int>>(params["b"]);
return func4(a,b);
}
typedef map<string, vector<map<string, any>>> FeatureMap;
vector<vector<std::any>> executor(map<string, vector<map<string, any>>> featureMap)
{
vector<vector<std::any>> res;
for (auto it=featureMap.begin(); it!=featureMap.end(); it++)
{
vector<std::any> currentRes;
if (it->first=="func1") {
for (auto paramIt=it->second.begin(); paramIt!=it->second.end(); paramIt++)
currentRes.push_back(func1Wrapper(*paramIt));
}
if (it->first=="func2") {
for (auto paramIt=it->second.begin(); paramIt!=it->second.end(); paramIt++)
currentRes.push_back(func2Wrapper(*paramIt));
}
if (it->first=="func3") {
for (auto paramIt=it->second.begin(); paramIt!=it->second.end(); paramIt++)
currentRes.push_back(func3Wrapper(*paramIt));
}
if (it->first=="func4") {
for (auto paramIt=it->second.begin(); paramIt!=it->second.end(); paramIt++)
currentRes.push_back(func4Wrapper(*paramIt));
}
res.push_back(currentRes);
}
return res;
}
int main()
{
FeatureMap fm;
fm["func1"] = { {{"a", 1}, {"b", 2}, {"c", 3}} , {{"a", 3}, {"b", -4}, {"c", 5}} };
fm["func2"] = { {{"a", 2}, {"b", 2}} , {{"a", 3}, {"b", -4}} };
fm["func3"] = { {{"a", 3}, {"b", "hello"s}} , {{"a", 3}, {"b", "123"s}} };
fm["func4"] = { {{"a", 4}, {"b", vector<int>({1,2,3})}}, {{"a", 3}, {"b", vector<int>({3,4,5})}} };
auto res = executor(fm);
auto func1Res = res[0], func2Res = res[1], func3Res = res[2], func4Res = res[3];
cout << any_cast<int>(func1Res[0]) << " " << any_cast<int>(func1Res[1]) << "\n";
cout << any_cast<double>(func2Res[0]) << " " << any_cast<double>(func2Res[1]) << "\n";
cout << any_cast<int>(func3Res[0]) << " " << any_cast<int>(func3Res[1]) << "\n";
cout << any_cast<int>(func4Res[0]) << " " << any_cast<int>(func4Res[1]) << "\n";
return 0;
}
I am converting a Python library to C++, it uses dict() everywhere.
A 1-1 conversion is like the code above: an executor accept a list of function, each function can have different parameter types and length. I store the parameters in a map<string, std::any> params, and for each function I have to manually extract the parameter then manually call the function (like func1Wrapper).
This code is very tedious to use and update. More importantly, it's very slow since there are map and std::any everywhere. I wish to use template to do as much thing as possible at compile time.
Is there anyway to convert the above code to using template? The executor should be able to accept any function with any parameter (different length, different types, ...). Instead of using a map<string, std::any> params, a user must give the function parameters in the correct order.
Edit: if the above is impossible, then what should I use to achieve similar functionality? Basically, the executor should be able to perform:
vector<vector<std::any>> res;
vector<vector<vector<std::any>> param_list;
for (i=0; i<function_list.size(); i++):
{
vector<std::any> currentRes;
for (j=0; j<param_list[i].size(); j++)
currentRes.push_back(function_list[i](param_list[i][j]));
res.push_back(currentRes);
}
while using as much compile-time stuffs as possible.
The executor should be able to accept any function with any parameter (different length, different types, ...).
You can use a combination of perfect forwarding and variadic templates as shown below. In the program shown, the function template forwardToArbitFunc<> accepts any number of function call arguments and forwards each of them to another function(which is also passed as the first argument to the function template).
#include <iostream>
#include<string>
//this function template forwards its arguments to arbitrary function
template<typename T, typename... Ts> void forwardToArbitFunc(T g,Ts&&... xs)
{
g(std::forward<Ts>(xs)...); // forward all xs to g()
}
void func()
{
std::cout<<"parameterless func called"<<std::endl;
}
void func2(int a)
{
std::cout<<"one parameter func2 called"<<std::endl;
}
void func3(std::string a, int b)
{
std::cout<<"two parameter func3 called"<<std::endl;
}
void func4(std::string a, std::string b, float c, double d)
{
std::cout<<"four parameter func4 called"<<std::endl;
}
int main()
{
forwardToArbitFunc(func);
forwardToArbitFunc(func2, 3);
forwardToArbitFunc(func3, "some string", 5);
forwardToArbitFunc(func4, "some string", "another string", 4.4, 5.5);
return 0;
}
Demo
#include <algorithm>
#include <array>
#include <iostream>
int main() {
std::array<int, 10> s{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
struct {
bool operator()(int a, int b) const
{
return a < b;
}
} customLess;
std::sort(s.begin(), s.end(), customLess);
for (auto a : s) {
std::cout << a << " ";
}
std::cout << '\n';
return 0;
}
I want to sort the array using std : : sort. The code above works fine, but when I try with template array in my main task (GArr<int, 5> arr{5, 2, 3, 4, 1};) the compiler gives the following
error: no match for 'operator-' (operand types are 'Iterator' and
'Iterator')|
How can I fix it?
I created a foreach() function, and it should print values of an array, but it tells me this:
no matching function for call to 'foreach(std::array<int, 4>&, void(&)(int))'
And also:
mismatched types 'unsigned int' and 'long unsigned int'
But when I try to use vectors instead of arrays, or on line 11 use template<unsigned int N> instead of unsigned int, if I use long unsigned int, it works fine.
So, why do I need to use long unsigned int?
And what does the "no matching function" error mean with arrays?
#include<iostream>
#include<string>
#include<array>
typedef void(*func)(int);
void print(int value) {
std::cout << "value is : " << value << std::endl;
}
template<unsigned int N>
void foreach(std::array<int, N>& values, func print) {
int value;
for(int i = 0; i < values.size(); i++) {
value = values[i];
print(value);
}
}
int main() {
std::array<int, 4> arr = { 0, 1, 2, 3 };
foreach(arr, print);
return 0;
}
With vectors:
#include<iostream>
#include<string>
#include<vector>
typedef void(*func)(int);
void print(int value) {
std::cout << "value is : " << value << std::endl;
}
void foreach(std::vector<int>& values, func print) {
int value;
for(int i = 0; i < values.size(); i++) {
value = values[i];
print(value);
}
}
int main() {
std::vector<int> v = { 0, 1, 2, 3 };
foreach(v, print);
return 0;
}
The template for std::array does not take an unsigned int, it takes a std::size_t, which may or may not (probably not) be defined as unsigned int:
template<size_t N>
void foreach(std::array<int, N>& values, func print);
A better option is to make your function be container-agnostic instead, by passing it iterators instead of the actual container, eg:
#include <iostream>
#include <string>
#include <array>
#include <vector>
typedef void(*func)(int);
void print(int value) {
std::cout << "value is : " << value << std::endl;
}
template<typename Iter>
void foreach(Iter begin, Iter end, func print) {
while (begin != end) {
print(*begin);
++begin;
}
}
int main() {
std::array<int, 4> arr = { 0, 1, 2, 3 };
foreach(arr.begin(), arr.end(), print);
std::vector<int> v = { 0, 1, 2, 3 };
foreach(v.begin(), v.end(), print);
return 0;
}
Not only does this allow the function to work with multiple containers, but also with different element types, if you change the print parameter to be a template as well, eg:
#include <iostream>
#include <string>
#include <array>
#include <vector>
void printInt(int value) {
std::cout << "value is : " << value << std::endl;
}
void printStr(const std::string &value) {
std::cout << "value is : " << value << std::endl;
}
template<typename Iter, typename Callable>
void foreach(Iter begin, Iter end, Callable print) {
while (begin != end) {
print(*begin);
++begin;
}
}
int main() {
std::array<int, 4> arr = { 0, 1, 2, 3 };
foreach(arr.begin(), arr.end(), printInt);
std::vector<std::string> v = { "hello", "world", "joe", "smoe" };
foreach(v.begin(), v.end(), printStr);
return 0;
}
This is the exact strategy that standard algorithms use, such as std::for_each() (which you should be using instead of writing your own) 1, eg:
#include <iostream>
#include <string>
#include <array>
#include <vector>
#include <algorithm>
int main() {
std::array<int, 4> arr = { 0, 1, 2, 3 };
std::for_each(arr.begin(), arr.end(),
[](int value) { std::cout << "value is : " << value << std::endl; }
);
std::vector<std::string> v = { "hello", "world", "joe", "smoe" };
std::for_each(v.begin(), v.end(),
[](const std::string &value) { std::cout << "value is : " << value << std::endl; }
);
return 0;
}
1: C++20 introduced a new Ranges library that has algorithms to act on whole containers.
Because the second template parameter for std::array is std::size_t, not unsigned int. Compiler cannot infer the convertion between types in template function. And it just happens that std::size_t in your compiler is a typedef on long unsigned int, so that's what it suggests.
You can make it work in two ways:
Change the template type to std::size_t
Provide template parameter explicitly when calling:
foreach<4>(v, print);
I am trying to write a function which would Print Data on the console. The function is to be templated as it should accept different types of Data.
The code is as shown below:
template<typename DataType>
void PrintData(DataType *X)
{
for (DataType Data : X)
{
cout << Data << "\t";
}
cout << endl;
}
int main()
{
int nArray[7] = { 7, 5, 4, 3, 9, 8, 6 };
double dArray[5] = { 4.3, 2.5, -0.9, 100.2, 3.0 };
PrintData(nArray);
PrintData(dArray);
system("pause");
return EXIT_SUCCESS;
}
I get an error that variable Data is undeclared in the templated function PrintData.
error C2065: 'Data' : undeclared identifier
error C3312: no callable 'begin' function found for type 'double *'
error C3312: no callable 'begin' function found for type 'int *'
error C3312: no callable 'end' function found for type 'double *'
error C3312: no callable 'end' function found for type 'int *'
Any help would be appreciated.
Thanks
Assuming you have included the iostream header file and the using namespace std; directive. Then your problems are:
You should not use DataType *. Your code makes X a pointer, which is different from array. Use DataType const& or DataType&& instead.
You have to include the iterator header file which provides the begin and end function for C-style array.
The following code works for me.
#include <iostream>
#include <iterator>
using namespace std;
template<typename DataType>
void PrintData(DataType const& X)
{
for (auto Data : X)
{
cout << Data << "\t";
}
cout << endl;
}
int main()
{
int nArray[7] = { 7, 5, 4, 3, 9, 8, 6 };
double dArray[5] = { 4.3, 2.5, -0.9, 100.2, 3.0 };
PrintData(nArray);
PrintData(dArray);
return EXIT_SUCCESS;
}
As commented by Igor Tandetnik, you may use template<struct DataType, size_t N> if you want to refer the size of the array.
Update:
With template<struct DataType> and DataType *X, DataType is deduced as int and double, and X is a pointer which is not a container.
With template<struct DataType, size_t N> and DataType (&X)[N], DataType is deduced as int and double, and X is an array which can be used with range-based for loop.
With template<struct DataType> and DataType&& X or DataType const& X, DataType is deduced as int[7] or double[5], and X is an array as well.
The problem is that you're passing the name of the array (e.g., nArray), which is just a pointer to the first element, basically. However, new-style for loops expect something on which you can call begin and end - a range.
The following changes make it work by using a vector instead of an array. Note that there are very few differences otherwise, and, in general, very few reason to use C-style arrays in contemporary C++.
#include <iostream>
#include <vector>
using namespace std;
template<typename DataType>
void PrintData(const DataType &X)
{
for (const auto &Data : X)
{
cout << Data << "\t";
}
cout << endl;
}
int main()
{
vector<int> nArray = { 7, 5, 4, 3, 9, 8, 6 };
vector<double> dArray = { 4.3, 2.5, -0.9, 100.2, 3.0 };
PrintData(nArray);
PrintData(dArray);
system("pause");
return EXIT_SUCCESS;
You have some problems:
1) DataType must be a container. So, try to use:
std::vector<int> nArray = { 7, 5, 4, 3, 9, 8, 6 };
std::vector<double> dArray = { 4.3, 2.5, -0.9, 100.2, 3.0 };
2) You are not going to change the container. It's better to pass container by const reference:
template<typename DataType>
void PrintData(const DataType & X);
3) Change the loop like this:
for (const auto & value : X) {
std::cout << value << "\t";
}
Code example:
#include <iostream>
#include <vector>
template<typename DataType>
void PrintData(const DataType & X) {
for (const auto & value : X) {
std::cout << value << "\t";
}
std::cout << std::endl;
}
int main() {
std::vector<int> nArray = { 7, 5, 4, 3, 9, 8, 6 };
std::vector<double> dArray = { 4.3, 2.5, -0.9, 100.2, 3.0 };
PrintData(nArray);
PrintData(dArray);
return 0;
}
As Igor suggested, If at all you wish to use DataType * then you need to do something like this
#include <iostream>
#include <iterator>
using namespace std;
template <typename DataType, size_t N>
void PrintData(DataType (&X)[N])
{
for (auto i : X)
cout << i << "\t";
cout << endl;
}
int main()
{
int nArray[7] = { 7, 5, 4, 3, 9, 8, 6 };
double dArray[5] = { 4.3, 2.5, -0.9, 100.2, 3.0 };
PrintData(nArray);
PrintData(dArray);
return EXIT_SUCCESS;
}
Output
7 5 4 3 9 8 6
4.3 2.5 -0.9 100.2 3
Explanation:
If you see void PrintData(int* nArray); & void PrintData(int (&nArray)[7] );
are similar declarations, except that seconds one tells where array ends.
Template function
template <typename DataType, size_t N>
void PrintData(DataType (&X)[N])
is deduced as'
void PrintData(int (&nArray)[7] )
You could also write
void PrintData(int (&nArray)[7] )
{
for (auto i : nArray)
cout << i << "\t";
cout << endl;
}
I've written a simple test program to try to learn how to use template static member functions in C++. The code compiles, but doesn't work right (prints out some garbage). I guess I'm using the right syntax. I've read this or this and some other stuff but still don't know what I'm doing wrong. The code below:
#include <iostream>
using namespace std;
class Util {
public:
Util();
virtual ~Util();
template <typename T> static void printTab(T tab[]);
};
template <typename T>
void Util::printTab(T tab[]) {
for (unsigned int i=0; i<sizeof(tab)/sizeof(tab[0]); i++) {
cout << tab[0] << " ";
}
cout << endl;
}
int main() {
float tabFloat[5] {1, 2, 3, 4, 5};
unsigned char tabChar[3] {1, 2, 3};
Util::printTab(tabFloat);
Util::printTab(tabChar);
return 0;
}
Any hints appreciated.
You need to pass the size as another template argument :
#include <iostream>
using namespace std;
class Util {
public:
Util();
virtual ~Util();
template <typename T,int N> static void printTab(T (&tab)[N])
{
for (int i=0; i<N; i++) {
cout << tab[i] << " ";
}
cout << endl;
}
};
int main() {
float tabFloat[5] {1, 2, 3, 4, 5};
unsigned char tabChar[3] {1, 2, 3};
Util::printTab(tabFloat);
Util::printTab(tabChar);
}
sizeof(tab) is the size of a T*, it will not return the size of the whole array. You need to pass that in yourself as another argument to the function. See here for an explanation and another potential workaround: When a function has a specific-size array parameter, why is it replaced with a pointer?
Note that the second printTab will not output readable characters. If you want to see something printed out, try with:
unsigned char tabChar[3] {'1', '2', '3'};
How about trying, you need to send the size of the array when calling a function:
#include <iostream>
using namespace std;
class Util {
public:
Util();
virtual ~Util();
template <typename T> static void printTab(T tab[], size_t sz);
};
template <typename T>
void Util::printTab(T tab[], size_t sz) {
for (unsigned int i=0; i<sz; i++) {
cout << tab[i] << " ";
}
cout << endl;
}
int main() {
float tabFloat[5] {1, 2, 3, 4, 5};
unsigned char tabChar[3] {1, 2, 3};
Util::printTab(tabFloat, sizeof(tabFloat)/sizeof(float));
Util::printTab(tabChar, sizeof(tabChar)/sizeof(char));
return 0;
}
I'd pass the number of elements of T as a function argument or use a STD container such as a Vector.
Your for loop is just printing the first element tab[0] not tab[i]
Your initialization of tabFloat and tabChar are missing =
float tabFloat[5] {1, 2, 3, 4, 5};
unsigned char tabChar[3] {1, 2, 3};
(also I'd use 65, 66, 67 instead of 1,2,3 for console readability in your testing)
float tabFloat[5] = {1, 2, 3, 4, 5};
unsigned char tabChar[3] = { 65, 66, 67};