Consider following example:
#include <algorithm>
#include <iterator>
#include <vector>
template<class InputIterator, class T>
bool privIsElementOf(const T& element, InputIterator first, InputIterator last)
{
return ( std::find(first, last, element) != last );
}
template<class Container, class T>
bool isElementOf(const T& element, const Container & cont)
{
return privIsElementOf( element, std::begin(cont), std::end(cont) );
}
template<class T>
bool isElementOf(const T& element, const std::initializer_list<T> iList)
{
return privIsElementOf( element, std::begin(iList), std::end(iList));
}
int main()
{
std::vector<int> myVec { 1 , 3 , 5};
bool isElement = isElementOf(3, myVec);
bool isElement2 = isElementOf(3, {1 , 3, 5 });
return 0;
}
It compiles well with the second isElementOf template with the initializer_list. Nevertheless the content more or less the same as the first template. It uses std::begin and std::end.
When I remove the second template, it shows following compile error:
initList.cpp: In function ‘int main()’:
initList.cpp:31:47: error: no matching function for call to ‘isElementOf(int, )’
bool isElement2 = isElementOf(3, {1 , 3, 5 });
^
initList.cpp:31:47: note: candidate is:
initList.cpp:12:6: note: template bool isElementOf(const T&, const Container&)
bool isElementOf(const T& element, const Container & cont)
^
initList.cpp:12:6: note: template argument deduction/substitution failed:
initList.cpp:31:47: note: couldn't deduce template parameter ‘Container’
bool isElement2 = isElementOf(3, {1 , 3, 5 });
^
Can anyone explain me the problem? The template is just asking for a class that provides compatibility with std::begin and std::end. Why is the template for container not working for initialiser list? Is there a way to solve the problem with only one template?
Live example
A function parameter for which the associated argument is an initializer list (8.5.4) but the parameter does not have
std::initializer_listor reference to possibly cv-qualifiedstd::initializer_listtype
is a non-deduced context (§14.8.2.5 [temp.deduct.type]/p5), so the compiler can't deduce Container. A braced-init-list by itself has no type.
One possibility is to provide a default template argument to cover this case:
template<class T, class Container = std::initializer_list<T>>
bool isElementOf(const T& element, const Container & cont)
{
return privIsElementOf( element, std::begin(cont), std::end(cont) );
}
Note that you shouldn't use a initializer_list default argument unless you are sure that the code won't be affected by its copying semantics - the lifetime of the underlying array isn't affected by any copying of the initializer_list object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With