Search code examples
c++multithreadingc++20std-span

Why do I need to pass std::span for a string argument when using std::thread in C++?


I've written the following code, which creates a thread that repeatedly prints a string.

In this code, I can directly pass a string as an argument to the repeat() function in the main() function. However, when I want to create a thread that calls the repeat() function, I have to pass the string inside a std::span.

Why is this the case? Why does std::thread require std::span for a string argument when the repeat() function itself doesn't?

Errors:

Error C2780: 'std::invoke' expects 1 arguments, 3 provided.
Error C2893: Failed to specialize function template 'std::invoke'.

Visual Studio 2019, Enterprise Edition. C++20

#include <span>
#include <iostream>

void repeat1(std::span<const char> str, int n)
{
    if (n > 0)
    {
        std::cout << str.data() << std::endl;
        repeat1(str, n - 1);
    }
}

void repeat2(std::string_view str, int n)
{
    if (n > 0)
    {
        std::cout << str.data() << std::endl;
        repeat2(str, n - 1);
    }
}

int main()
{
    repeat1("I am exploring...", 3); //it works 
    repeat2("I am exploring...", 3); //it works 
    //std::thread t(repeat2, "I am exploring...", 5); // It works
    //std::thread t(repeat1, std::span < const char>("I am exploring..."), 5); // It works
    std::thread t(repeat1, "I am exploring...", 5); // It doesn't compile
    std::cout << "Hello from main()\n";
    t.join();
}

Solution

  • std::thread copies the argument to the decayed type before invoking.

    In your example, the string literal decays to const char*, which is no longer a range, and thus cannot be used to construct a std::span.