5

Consider a class which inherits from a std container with a template constructor which calls the underlying constructor of the container. This template constructor works for the simple copy and move constructor but not for the initializer_list ctor.

template<typename container_T>
class test : public container_T {
public:
  using container_type = container_T;

  test() {} 

  // templated constructor
  template<typename T>
  test(T t)
    : container_T(t) {}

   // without this it won't compile
  test(std::initializer_list<typename container_T::value_type> l)
    : container_T(l) {}
};

int main() {    
  test<std::deque<int>> vdi1;
  test<std::deque<int>> vdi2({1,2,3,4,5,6,7,8,9});

  std::cout << "vdi2 before:" << std::endl;
  for(auto it : vdi2)
    std::cout << it << std::endl;

  test<std::deque<int>> vdi3(std::move(vdi2));

  std::cout << "vdi2 before:" << std::endl;
  for(auto it : vdi2)
    std::cout << it << std::endl;

  std::cout << "vdi3 before:" << std::endl;
  for(auto it : vdi3)
    std::cout << it << std::endl;

  return 0;
}

If I remove the initializer_list constructor vdi2 won't compile. So my question: Why is the initializer_list not deduced by the template constructor? And is it possible to do so?

6
  • Actually, it is not a copy or move, they're declared implicitly, in addition to your ctor. And it doesn't work for initializer_lists as they cannot be/are not deduced. Commented Oct 20, 2013 at 19:06
  • 3
    Why don't you use inheriting ctors? using container_T::container_T; Live example Commented Oct 20, 2013 at 19:08
  • @DyP why should itinherit copy or move ctors? Commented Oct 20, 2013 at 19:08
  • Edited comment (.. still a word missing: Actually, it is not a copy or move _ctor_). What I meant was: a ctor template is never a copy or move ctor. Commented Oct 20, 2013 at 19:11
  • 1
    Looks like you wanna read stackoverflow.com/questions/5733828/… Commented Oct 20, 2013 at 19:56

1 Answer 1

8

why is the initializer_list not deduced by the templated constructor?

The reason is that {1,2,3,4,5,6,7,8,9} is just a synctatic construct that doesn't have a type. Therefore, the compiler cannot deduce a type T for this synctatic construct and the first constructor fails.

However, by special Standard rules std::initializer_list<T> (among other things) can be construct from this synctatic construct and T can be deduced to int. Hence the second constructor works.

By constrast with function template argument type deduction, with

auto x = {1,2,3,4,5,6,7,8,9};

the compiler sets the type of x to be std::initializer_list<int>. There are also special Standard rules that says it must be so. Strictly speaking this is not type deduction because, as said above, {1,2,3,4,5,6,7,8,9} doesn't have a type to be deduced. (The only type deduction happening here is T = int in std::initializer_list<T>.) Here the compiler chooses (it doesn't deduce) the type of x to be std::initializer_list<int>. In any case, there's no harm to use the abuse of language of saying that the type of x is deduced to std::initializer_list<int>.

Finally, as DyP said in the comments, what you probably want is inheriting all constructors (not only those taking one argument) from the base container class. You can do this by removing all the constructors that you currently have and add just this line to test:

using container_type::container_type;
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.