I've been trying to use perfect forwarding with a parameter pack that I recursively unpack, and that made me realize I don't really understand the rules that govern how overloads for a given function are selected in the presence of universal references.
My confusion was motivated by some code similar to the following:
#include <iostream>
template<class T>
void write(const T& data)
{
std::cout << "Called write(const T& data)" << std::endl;
}
template<class T, class ...U>
void write(T&& obj, U&&... objs)
{
std::cout << "Called write(T&& obj, U&&... objs)" << std::endl;
}
int main(int, char**)
{
int j = 0;
write(j);
return 0;
}
When run, the void write(T&& obj, U&&... objs) overload is selected, but if I change the signature of void write(const T& data) to void write(const T data), void write(T& data), or void write(T data) then that function is called.
Why is the void write(const T& data) overload not selected but void write(const T data), void write(T& data), or void write(T data) are?
Edit: I originally though that the issue may have been related to use of std::forward; however it appears to be more a result of the universal references. My original example is below:
#include <iostream>
void write()
{
std::cout << "Writing nothing" << std::endl;
}
void write(const char* data)
{
std::cout << "Writing const char*: " << data << std::endl;
}
template<class T>
void write(const T& data)
{
std::cout << "Writing generic: " << data << std::endl;
}
template<class T, class ...U>
void write(T&& obj, U&&... objs)
{
write(std::forward<T>(obj));
write(std::forward<U>(objs)... );
}
int main(int, char**)
{
int j = 0;
write("a", j);
return 0;
}