Help to understand the logic of the compiler. Why do these errors occur? I also ask you to tell me how to pass template functions to the stream.

The user- void GenSeqByte(T&& stream, size_t byte) method void GenSeqByte(T&& stream, size_t byte) . Where stream universal reference to an abstract stream / container / ... for which the write(T stream, const char *mem, size_t count) function is defined write(T stream, const char *mem, size_t count) .

 template<typename T> void GenSeqByte(T&& stream, size_t byte) { std::mutex mtx; std::vector<std::thread> threads; for (size_t i = 0; i < std::thread::hardware_concurrency(); ++i) { threads.push_back(std::thread(GenAndWriteSeq, std::ref(stream), std::ref(byte), std::ref(mtx))); } for (auto &t : threads) { t.join(); } } 

Function code void GenAndWriteSeq(T&& stream, size_t &bytes, std::mutex &m) .

 template<typename T> void GenAndWriteSeq(T&& stream, size_t &bytes, std::mutex &m) { std::random_device seed; std::mt19937 gen(seed()); std::uniform_int_distribution<int> dist; // 1 KByte buffer. constexpr size_t bufSize = 1024 / sizeof(int); int buf[bufSize]; while (true) { for (size_t i = 0; i < bufSize; ++i) { buf[i] = dist(gen); } if (bytes > 0) { std::lock_guard<std::mutex> lck(m); if (bytes > 0) { stream.write(reinterpret_cast<char *>(buf), bytes > bufSize ? bufSize : bytes); if (bytes > bufSize) { bytes -= bufSize; continue; } } } return; } } 

Compilation fails with error: Ошибка C2440 <function-style-cast>: невозможно преобразовать "initializer list" в "std::thread" in the string

 threads.push_back(std::thread(GenAndWriteSeq, std::ref(stream), std::ref(byte), std::ref(mtx))); 

If you make some changes, the compilation succeeds.

 threads.push_back(std::thread(GenAndWriteSeq<T>, std::ref(stream), std::ref(byte), std::ref(mtx))); 

Calling code

 std::ofstream f("numbers.txt", std::ofstream::binary); GenSeqByte(f, fileSize); 

Everything works until the moment we pass the GenSeqByte rvalue function.

 GenSeqByte(std::ofstream("numbers.txt", std::ofstream::binary), fileSize); 

Mistake.

 Ошибка C2672 "std::invoke": не найдена соответствующая перегруженная функция Ошибка C2893 Сбой при специализации функции-шаблона "unknown-type std::invoke(_Callable &&,_Types &&...) noexcept(<expr>)" 
  • GenAndWriteSeq becomes a function only after specifying template arguments, &GenAndWriteSeq<T> - VTT
  • @VTT yes, if you specify a template agrument, the program is compiled for lvalue objects. But what to do with GenSeqByte(std::ofstream("numbers.txt", std::ofstream::binary), fileSize); ? - PilgrimFromMars
  • So do not use the universal link here. You then do not forward this object anywhere. - VTT

1 answer 1

In the case of an rvalue argument, type T for GenSeqByte deduced as Т == std::ofstream . Then the GenAndWriteSeq<T> function will take a parameter of type std::ofstream && . And you pass std::ref(stream) . std::ref(stream) not a valid argument for std::ofstream && . std::ref generates an analogue of an lvalue link. It cannot be used to initialize an rvalue link.

Here you could simply switch to using lvalue-references inside GenSeqByte , explicitly specifying T & as a GenAndWriteSeq argument for GenAndWriteSeq

 threads.push_back(std::thread(GenAndWriteSeq<T &>, std::ref(stream), std::ref(byte), std::ref(mtx)));