I got a (simplified) function Foo
template<typename It, typename T>
void Foo(It begin, It end, T&& CallBar)
{
CallBar(begin, end);
}
And another simplified function Bar
template<typename It>
It Bar(It begin, It end)
{
return begin;
}
When I call both functions in the following way
std::vector<int> v{ 3, 8, 2, 5, 1, 4, 7, 6 };
Foo(v.begin(), v.end(), Bar);
I get the error
'declaration' : could not deduce template argument for 'identifier'
What else do I have to specify to make it compile?
The issue here is that since Bar is a function template, it does not know which Bar you want. You have to tell it what version of Bar to use. One way to do that is by specifying the template type. You can do that like:
Foo(v.begin(), v.end(), Bar<decltype(v.begin())>);
If you would like to not have to specify the template type, which to be honest, is a little brittle then we can wrap the call to Bar in a lambda. This will allow the compiler to do all of the type deduction for us which is a lot easier to maintain. For example if you change the iterator type nothing you neede to be changed unlie the previous solution. Thanks to 0x499602D2 that would be
Foo(v.begin(),v.end(),[](auto b,auto e){return Bar(b,e);})
What else do I have to specify to make it compile?
By example
template<typename It>
void Foo(It begin, It end, It(* CallBar)(It, It))
{
CallBar(begin, end);
}
You can use template templates to help solve this. As far as I know, it requires you to wrap your Bar function in a functor. By placing the functor template parameter first, you can specify it and let the iterator type be deduced.
#include <vector>
// T is a type that takes a 'class' template argument
template<template<class> class T, class It>
void Foo(It begin, It end)
{
T<It>()(begin, end);
}
template<typename It>
struct Bar
{
It operator()(It begin, It end)
{
return begin;
}
};
int main()
{
std::vector<int> v{ 3, 8, 2, 5, 1, 4, 7, 6 };
Foo<Bar>(v.begin(), v.end());
return 0;
}
Related
I have been writing some functions that take a template called It, which should be an iterator. Then I use the It::value_type for some functionality. This has been working for most containers I have tried but fails for std::array. If I do use an std::array I get the error
error: ‘long unsigned int*’ is not a class, struct, or union type
So I see the problem, the iterator for the std::array is just a pointer, which makes sense to me. Therefore it has no ::value_type defined. But how can I make my templated code so that this works for std::array and std::vector, std::list etc?
I made a MWE, the function in it just a silly pathological example that shows my problem
#include <vector>
#include <iostream>
#include <array>
template <class It>
void print_accumulate(It first, It last) {
typename It::value_type result{}; // What do I write here??
while (first != last) {
result += *first;
++first;
}
std::cout << result << "\n";
}
int main() {
std::vector<size_t> v = {1, 2, 3, 4, 5}; /* Replacing with std::array<size_t, 5> gives error */
print_accumulate(v.begin(), v.end());
}
The above works just fine for just about every container I've tried, vector, list, set etc. However, when I try to run the code by replacing the std::vector<size_t> with std::array<size_t, 5>, i get the error message I gave.
Thanks in advance!
Use iterator_traits
template <class It>
void print_accumulate(It first, It last) {
typename std::iterator_traits<It>::value_type result{}; // use iterator_traits
while (first != last) {
result += *first;
++first;
}
std::cout << result << "\n";
}
I want to write a function my_func that can be called as so, but does not care that v is a std::vector, it could be any STL container. A bit like std::for_each:
std::vector<std::string> v = {...};
my_func(v.begin(), v.end());
But I cannot figure out the function signature.
void my_func(??? i1, ??? i2)
{
std::for_each(i1, i2, ...); // dumb example implementation
}
I am not great at template programming so even looking at the function declaration for std::for_each is not helping me.
Is there an easy implementation or is this fundamentally going to get messy with template vars?
It depends on how generic you want the function to be. If the iterator types have to match, then
template <typename T>
void my_func(T i1, T i2)
{
std::for_each(i1,i2,...); //dumb example implementation
}
is all you need. If you want them to be able to be different, then you just need another template parameter like
template <typename T, typename U>
void my_func(T i1, U i2)
{
std::for_each(i1,i2,...); //dumb example implementation
}
Finally, if you don't like dealing with templates you can use a lambda instead and let the compiler take care of this for you. That would give you
auto my_func = [](auto i1, auto i2)
{
std::for_each(i1,i2,...); //dumb example implementation
};
You could write a templated function
template<typename Iterator>
void my_func(Iterator startIter, const Iterator endIter)
{
std::for_each(startIter, endIter, /* lambda */);
}
In case of wondering, how to pass the third parameter of the std::for_each, you could provide one more template parameter
const auto defaultCallable = [](auto element){ }; // does nothing
template<typename Iterator, typename Callable = decltype(defaultCallable)>
void my_func(Iterator startIter, const Iterator endIter, Callable func = {})
{
std::for_each(startIter, endIter, func);
}
The syntax is not too obscure! The following way uses the range for at the point of use:
template <template<typename...> class Iterable, typename T>
void foo(
const Iterable<T>& y // the container
){
for (auto&& e : y){
// e is the 'thingy' in the container.
}
}
and you can pass any iterable container of arbitrary type to foo.
I am attempting to write a template function that iterates over a user-specified field within some collection of structs. For example, I want to write the following C++:
struct Example {
int a;
bool b;
};
template<std::function<Field& (Class)> GetField, typename Field, typename Class>
void myFunc(std::iterator<Class> begin, size_t const length) {
cout << length << endl;
for (size_t i{ 0 }; i < length; ++begin, ++i) {
Field const &field{ GetField(*begin) };
// Forward field to some other template function
anotherTemplateFunction<Field>(field);
}
}
void main() {
Example exArray[]{ {5, true}, {8, false} };
std::list<Example> exList{ exArray, exArray + _countof(exArray) }
// Examples of how I would like to call myFunc...
myFunc<Example::a>(exArray, _countof(exArray));
myFunc<Example::b>(exList.begin(), exList.size());
}
The above doesn't work, but hopefully the intent is clear. How can I write the myFunc template method to accomplish generic iteration over some field of each iterated item? Alternatively, if there is some way (in Boost or the Standard Library) to directly create an iterator over exArray[i].a, that would also be acceptable.
What I usually use is something like:
void main() {
std::array<Example, 2> exArray{ {5, true}, {8, false} };
std::list<Example> exList{ exArray.begin(), exArray.end() };
auto access_a = [](Example& e)->int&{ return e.a;};
auto access_b = [](Example& e)->bool&{ return e.b;};
myFunc(exArray.begin(), exArray.end(), access_a);
myFunc(exList.begin(), exList.end(), access_b);
}
template<class ForwardIt, class Accessor>
void myFunc(ForwardIt begin,ForwardIt end, Accessor accessor) {
cout << end - begin << endl;
for (auto it = begin; it != end; it++) {
// Forward field to some other template function
anotherTemplateFunction(accessor(*it));
}
}
Please notice how I used std::array instead of a raw c style array.
If you have access to a c++11 compiler, std::array (or std::vector) should always be preferred over raw c arrays. ES.27
In order to need less boilerplate code, consider using some serialization libraries which solve this "iterating over class fields" problem, for example boost serialization or magic get.
It's simple if you know the pointer to member syntax and the likes. Unfortunately is so rarely used, is kind of an esoteric feature of the language:
template <class T> void foo(T);
template <auto Field, class It>
auto myFunc(It begin, It end)
{
for (; begin != end; ++begin)
{
foo((*begin).*Field);
}
}
int main()
{
std::vector<Example> v{{5, true}, {8, false}};
myFunc<&Example::a>(v.begin(), v.end()); // will call foo<int>(5) , foo<int>(8)
myFunc<&Example::b>(v.begin(), v.end()); // will call foo<bool>(true) , foo<bool>(false)
}
For the template <auto Field you need C++17.
For C++11 the syntax is more verbose:
template <class T, class F, F T::* Field, class It>
void myFunc(It begin, It end)
{ /* same */ }
int main()
{
std::vector<Example> v{{5, true}, {8, false}};
myFunc<Example, int, &Example::a>(v.begin(), v.end()); // will call foo<int>(5) , foo<int>(8)
myFunc<Example, bool, &Example::b>(v.begin(), v.end()); // will call foo<bool>(true) , foo<bool>(false)
}
A little bit OT to your question, but I don't understand why you complicate yourself with that initialization of std::list. In C++ your first container of choice should be std::vector.
Also there is no std::iterator
I have the following class:
class Foo
{
public:
// Constructors here
private:
std::vector<X> m_data; // X can be any (unsigned) integer type
};
I want the following code to work:
Foo f0;
Foo f1(1); // and/or f1({1})
Foo f2(1, 2); // and/or f2({1, 2})
Foo f3(1, 2, 3); // and/or f3({1, 2, 3})
Foo f4(1, 2, 3, 4); // ... and so on
std::vector<int> vec = {1, 2, 3, 4};
Foo f5(vec);
Foo f6(vec.begin(), vec.end());
std::list<std::size_t> list = {1, 2, 3, 4};
Foo f7(list);
Foo f8(list.begin(), list.end());
std::any_iterable_container container = {1, 2, 3, 4};
Foo f9(container);
Foo f10(container.begin(), container.end());
// PS: I guess I only want containers/iterators that store individual
// values and not pairs (e.g., I don't want care about std::map
// because it does not make sense anyway).
So far I have tried to combine SFINAE, constructor overloading with all possible types, variadic templates, etc. Every time I fix one constructor case, others break down. Also, the code I write becomes very complex and hard to read. However, the problem seems quite simple and I guess I am just approaching it in a wrong way. Any suggestions on how to write the constructors (ideally in C++17), while also keeping the code as simple as possible, is more than welcome.
Thank you.
The simplest way to implement f1-f4 (which seem to take a variable number of arguments of a known type T that is not a container or iterator) ist this:
template<typename... Args>
Foo(T arg, Args... args) {...}
As this constructor takes at least 1 argument, there is no ambiguity with the default constructor f0. As the first argument is of type T, there is no ambiguity with the following constructors.
If you want to treat std::vector and std::list differently than other containers, you can create a partly specialized helper template to check if an argument is an instance of a given template:
template<typename>
struct is_vector : std::false_type {};
template<typename T, typename Allocator>
struct is_vector<std::vector<T, Allocator>> : std::true_type {};
And use it like this to implement f5 and f7:
template<typename T, Constraint = typename std::enable_if<is_vector<typename std::remove_reference<T>::type>::value, void>::type>
Foo(T arg) {...}
By testing for the respective iterator types of std::vector and std::list you can implement f6 and f8 in the same way.
You can check for the presence of member functions begin() and end() to implement f9 (I suppose) like this:
template<typename T>
Foo(T arg, decltype(arg.begin())* = 0, decltype(arg.end())* = 0) {...}
However, you'll have to explicitly disable this constructor for std::vector and std::list using the helper templates you created to avoid ambiguity.
To check if an argument is some iterator to implement f10, you can use std::iterator_traits:
template<typename T, typename Constraint = typename std::iterator_traits<T>::iterator_category>
Foo(T begin, T end) {...}
Again, you'll have to explicitly disable this constructor for the iterator types of std::vector and std::list.
The idea is to define the class like this:
template <typename X>
class Foo
{
public:
Foo() { };
Foo(initializer_list<int> l) :m_data(l) { };
template<typename container>
Foo(container const & c) :m_data(c.begin(), c.end()) {};
template<typename iterator>
Foo(iterator begin, iterator end) :m_data(begin, end) { };
private:
std::vector<X> m_data;
};
Where:
Foo() is the default (non-parametric) constructor.
Foo(initializer_list<int> l) accepts a list like {1, 2, 3}.
Foo(container const & c) accepts any container that supports begin and end iterators.
Foo(iterator begin, iterator end) initializes the class with begin and end iterators.
Usage:
Foo<int> f0;
Foo<int> f1({1});
Foo<int> f2({1, 2});
Foo<int> f3({1, 2, 3});
Foo<int> f4({1, 2, 3, 4});
std::vector<int> vec = {1, 2, 3, 4};
Foo<int> f5(vec);
Foo<int> f6(vec.begin(), vec.end());
std::list<size_t> list = {1, 2, 3, 4};
Foo<size_t> f7(list);
Foo<size_t> f8(list.begin(), list.end());
set<unsigned> container = {1, 2, 3, 4};
Foo<unsigned> f9(container);
Foo<unsigned> f10(container.begin(), container.end());
Assuming the class is defines as following:
template <class T>
class Foo
{
public:
[..]
private:
std::vector<T> m_data;
}
Let's break this task into sub-tasks:
Construct from iterators
template <class Iterator>
Foo (Iterator begin, Iterator end, typename Iterator::iterator_category * = 0)
: m_data(begin, end);
We will fill in our m_data from begin and end.
The third parameter will make sure only Iterator types that declare iterator_category will match this prototype. Since this argument has a default value of 0 and is never specified, it serves a purpose only during the template deduction process. When the compiler checks if this is the right prototype, if the type Iterator::iterator_category doesn't exist, it will skip it. Since iterator_category is a must-have type for every standard iterator, it will work for them.
This c'tor will allow the following calls:
std::vector<int> vec = {1, 2, 3, 4};
Foo<int> f(vec.begin(), vec.end());
-- AND --
std::list<std::size_t> list = {1, 2, 3, 4};
Foo<int> f(list.begin(), list.end());
Construct from container
template <class Container>
Foo (const Container & container, decltype(std::begin(container))* = 0, decltype(std::end(container))* = 0)
: m_data(std::begin(container), std::end(container));
We will fill our m_data from the given container. We iterate over it using std::begin and std::end, since they are more generic than their .begin() and .end() counterparts and support more types, e.g. primitive arrays.
This c'tor will allow the following calls:
std::vector<int> vec = {1, 2, 3, 4};
Foo<int> f(vec);
-- AND --
std::list<std::size_t> list = {1, 2, 3, 4};
Foo<int> f(list);
-- AND --
std::array<int,4> arr = {1, 2, 3, 4};
Foo<int> f(arr);
-- AND --
int arr[] = {1, 2, 3, 4};
Foo<int> f(arr);
Construct from an initializer list
template <class X>
Foo (std::initializer_list<X> && list)
: m_data(std::begin(list), std::end(list));
Note: We take the list as an Rvalue-reference as it's usually the case, but we could also add a Foo (const std::initializer_list<X> & list) to support construction from Lvalues.
We fill in our m_data by iterating over the list once again. And this c'tor will support:
Foo<int> f1({1});
Foo<int> f2({1, 2});
Foo<int> f3({1, 2, 3});
Foo<int> f4({1, 2, 3, 4});
Constructor from variable number of arguments
template <class ... X>
Foo (X ... args) {
int dummy[sizeof...(args)] = { (m_data.push_back(args), 0)... };
static_cast<void>(dummy);
}
Here, filling in the data into the container is a bit trickier. We use parameter expansion to unpack and push each of the arguments. This c'tor allows us to call:
Foo<int> f1(1);
Foo<int> f2(1, 2);
Foo<int> f3(1, 2, 3);
Foo<int> f4(1, 2, 3, 4);
Entire class
The final result is quite nice:
template <class T>
class Foo
{
public:
Foo () {
std::cout << "Default" << std::endl;
}
template <class ... X>
Foo (X ... args) {
int dummy[sizeof...(args)] = { (m_data.push_back(args), 0)... };
static_cast<void>(dummy);
std::cout << "VA-args" << std::endl;
}
template <class X>
Foo (std::initializer_list<X> && list)
: m_data(std::begin(list), std::end(list)) {
std::cout << "Initializer" << std::endl;
}
template <class Container>
Foo (const Container & container, decltype(std::begin(container))* = 0, decltype(std::end(container))* = 0)
: m_data(std::begin(container), std::end(container)) {
std::cout << "Container" << std::endl;
}
template <class Iterator>
Foo (Iterator first, Iterator last, typename Iterator::iterator_category * = 0)
: m_data(first, last) {
std::cout << "Iterators" << std::endl;
}
private:
std::vector<T> m_data;
};
How to create a lambda function that accepts iterators for vector,list,array?
Something like:
auto do_somthing=[](iterator beg,iterator end){
//code here
}
If you use C++14, generalized lambdas will solve your problem nicely.
auto do_something = [](auto begin, auto end) {
// code here
};
int x[]{ 1, 2, 3, 4 };
do_something(std::begin(x), std::end(x));
std::set<int> s{3, 4, 12, 55, 98 };
do_something(std::begin(s), std::end(s));
#rollbear answered this for C++14, using a generic lambda. In C++11, you can hand-code such a "generic lambda:"
struct GenericLambda
{
template <class It>
void operator() (It beg, It end) { /*:::*/ }
} do_something;
If you're limited to c++11, and you need the generic lambda because you're in a templated function where the container is a template argument, then you can get the iterator type like this:
template<class T>
void foo()
{
using iterator = typename T::iterator;
auto lambda = [](iterator beg,iterator end){}
}