I was struggling finding a better title. Here's the error: error C2440: 'initializing': cannot convert from 'initializer list' to 'Queue' It seems to be a very common error that I am getting and I expect that it is a common error in general. The problem occurs in operator<< :
template <typename T>
std::ostream& operator<<(std::ostream& out, bsTree<T>& tree) {
if (!tree.m_root)
return out;
using Nodeptr = typename bsTree<T>::Node*;
Queue<Nodeptr> q{ tree.m_root }; //this line right here
Nodeptr current{tree.m_root};
while (!q.empty()) {
current = q.front();
std::cout << current->data << '\n';
if (current->left)
q.push(current->left);
if (current->right)
q.push(current->right);
q.pop();
}
return out;
}
In Queue:
template <std::same_as<T>... Args>
Queue(Args&&... args) {
push(std::forward<T>(args)...);
}
It seems that the problem is that there is some difference between what the compiler deduces as T and the actual type of argument being different. This is the only constructor in Queue, the other takes no arguments. The problem goes away if std::same_as is replaced with typaname so there's something about this and I wonder what it is. As is with std::same_as if I use a function to return the address of the root node of the tree then it works but if it returns a reference to the private member variable holding the address of the root then again it's not working. Strangely when I defined a Nodeptr variable inside the operator<< and initialized it with tree.m_tree and then used that to initialize the Queue that didn't work. It seems identical to using a funcion to get the root address of the tree(for example if I hadn't made operator<< a friend of bsTree then I would have to use a function) but it doesn't work and I am curious why it wouldn't. using a simple typename... seems to solve all the problems in all of those cases. I guess I will use that for now and I will come back to find out what's happening :)
I tried typename... instead of std::same_as... and I was expecting that the problem would go away... I also just had the idea that the compiler probably creates references. To test this I tried this in operator<<
using Nodeptr = typename bsTree<T>::Node*;
Nodeptr current{ tree.m_root };
Nodeptr temp{ current };
Queue<Nodeptr> q{ std::move(temp)};
So this worked so I guess that I should use some std concept to remove the references etc to get the bare type. I tried this:
template <std::same_as<std::remove_cvref_t<T>>... Args>
Queue(Args&&... args) {
push(std::forward<T>(args)...);
}
I guess still not correct for some reason, this is giving the same error(after removing std::move) Any suggestions are welcome, thank you all in advance.
So this worked so I guess that I should use some std concept to remove the references etc to get the bare type.
You can check with the requires
-clause
template <typename... Args>
requires (std::same_as<T, std::remove_cvref_t<Args>> && ...)
Queue(Args&&... args) {
push(std::forward<T>(args)...);
}