Why is it legal to pass generic lambdas to std::thread() without any specialization, while, on the other hand, this is illegal with function templates.
The following demonstrates my query.
#include <thread>
template <class T>
void f(T t)
{
}
int main()
{
std::thread t([](auto i){}, 1); // Works
std::thread t(f, 1); // Doesn't work
std::thread t(f<int>, 1); // Works
t.join();
return 0;
}
C++ consists of many different kinds of things. Some of these things are: objecs, types, and templates. They are completely different things, that serve their own distinct, unique purposes. There's a right place in a C++ program to use an object, a right place to use a type, and a right place to use a template. When you have a right place for an object, you can't use a type or a template. When you have a right place to use a type you can't use an object or a template. When you have a right place to use a template you can't use an object or a type. This is fundamental to C++.
The parameters to a function call, or a constructor, are always objects. They are never types, or templates.
std::thread t([](auto i){}, 1); // Works
Both parameters are objects. This is correct. A lambda is an object, an instance of a unique, anonymous type. 1
is also an object: an integer whose value is 1.
std::thread t(f, 1); // Doesn't work
f
is not an object. It is a template.
std::thread t(f<int>, 1); // Works
This f<int>
is an object, a pointer to a function that was instantiated from a template.
An identifier that corresponds to a name of a template, by itself, results in a template. It does not result in a type, or an object. When you specify template parameters you end up with a type, and in a special case of a type that refers to a template function you get a pointer to the template function instance, an object (just like using the name of an ordinary non-template function, by itself, gives you a pointer to that function).