1

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();
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Sami
  • 513
  • 4
  • 11
  • 2
    If you don't use `std::span`, what happen then? What problems do that give you? Please [edit] your question to give us more details. – Some programmer dude Jul 16 '23 at 13:50
  • 1
    Or do you perhaps mean why you can't do `std::thread t(repeat, str, 5);` but you can call `repeat(str, 5)` directly? (Which I [can't replicate](https://godbolt.org/z/YchqWbEan)) Again, please [edit] your question to elaborate, give us more details, and if you get build errors then include them as well. Also please make sure you're showing us a proper [mre] of the *failing* code, and tell us what compiler and what version of it you're using. And the flags and options used when building. – Some programmer dude Jul 16 '23 at 13:55
  • You don't have to pass a std::span at all. Use [lambda expressions](https://en.cppreference.com/w/cpp/language/lambda) and you can capture any kind of object with ease and in a mode (reference or copy) you specify – Pepijn Kramer Jul 16 '23 at 14:16
  • @Someprogrammerdude I have edited the code. Sorry for not being clear. – Sami Jul 16 '23 at 14:29

1 Answers1

4

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.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
康桓瑋
  • 33,481
  • 5
  • 40
  • 90