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_list
or reference to possibly cv-qualifiedstd::initializer_list
type
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