Why can't I do this?

#include <iostream> #include <fstream> #include <vector> using namespace std; template <class Type, template <class, class = std::allocator<Type> > class Container> void print_container(Container<Type>&& container, ostream& os) { os << "{ "; for (auto& var : container) { os << var << " "; } os << "}"; } int main(int argc, char* argv[]) { std::vector<string> name; name.push_back("Igor"); name.push_back("Andrii"); print_container(name, cout); //print_container(vector<string>{"Igor", "Andrii"}, cout); // Работает без ошибок return 0; } 

I get errors:

 example.cpp:22:31: error: cannot bind 'std::vector<std::basic_string<char> >' lvalue to 'std::vector<std::basic_string<char> >&&' print_container(name, cout); ^ example.cpp:8:6: note: initializing argument 1 of 'void print_container(Container<Type>&&, std::ostream&) [with Type = std::basic_string<char>; Container = std::vector; std::ostream = std::basic_ostream<char>]' void print_container(Container<Type>&& container, ostream& os) { 
  • and why are there two ampersands? - Abyx

2 answers 2

write

 print_container(std::move(name), cout); 

yes and in a good way print_container should take a constant link, not r-value refenece ... although not, there is a universal link here, so the rules ... although not all the same r-value (after seeing another answer)

  • Yes, this is just an example. And without a move, is it possible to come up with something? - Ihor Kashpruk
  • without move signature print_container should accept const Container <Type> & container - xperious
  • Yes, I understand, thanks - Ihor Kashpruk

The problem with your code is that the template template parameters do not give a forwarding reference on output. But, apparently, you are trying to use it without understanding why it is needed, because In your example, there is no code that would mean type forwarding.

Because of the above problem, you get a function that takes an rvalue reference as the first parameter, but you pass in an lvalue object, so the compiler curses. The correct solution in this particular situation would be to use const Container<Type>& container as the function argument. After all, you do not change the container and do not transfer it to anywhere: other options are simply redundant here.

But if you ignore all of the above, you will notice one more thing: you don’t need a sample template parameter at all, because you don’t use what you brought out thanks to it anywhere! Therefore, if we rewrite an example like this:

 template <typename Container> void print_container(Container&& container, ostream& os) { os << "{ "; for (auto& var : container) { os << var << " "; } os << "}"; } 

then it will become

  1. Simpler.
  2. Having a forwarding link (although it is not needed).

The code from the question allowed us to find a bug in MSVC.

  • Then in the auto&& loop - int3
  • @ int3, let the author himself is engaged in the internal "finishing" of the function. - ixSci
  • And how is this generally possible - template <class Type, template <class, class = std::allocator<Type> > class Container> - without specifying the name of the parameter? How does the compiler know what type of parameter should be? Why not? template <class Type, template <class Type, class = std::allocator<Type> > class Container> ? by the way, so Visual C ++ easily understands ... - Mikhailo
  • @Mikhailo, the name doesn’t play a role there at all, and the default parameter can be set regardless of the presence of the name. If you do, then this is a redistribution of an already existing Type , and the result is nonsense. The fact that the studio is swallowing is one more of its bug. - ixSci
  • I do not understand ... it's that, you can declare, say, template<typename> class T; and then use T<int> , for example? - Mikhailo