Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializer list as container does not work

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

like image 651
meddle0106 Avatar asked Sep 09 '14 06:09

meddle0106


1 Answers

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-qualified std::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.

like image 193
T.C. Avatar answered Oct 04 '22 12:10

T.C.