0

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; } 
2
  • 2
    What's wrong with std::for_each()? And if it's the pair of iterators, why not just wrap it? Commented Jan 14, 2021 at 22:30
  • 1
    template<size_t N> seems like a better fit for void foreach Commented Jan 14, 2021 at 22:33

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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:

  1. Change the template type to std::size_t

  2. Provide template parameter explicitly when calling:

    foreach<4>(v, print);

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.