Reputation: 69
I posted a question yesterday but I didn't have a runnable example to give other users. I do now, so I deleted my old post.
I have some code that fails to build when I attempt to make and use std::threads()
and std::ref()
inside of a class. I do not understand the error messages that are produced, which all start with the line error: no matching function for call
or error: no type named ‘type’
.
I am using Clion and CMake, incase that matters. My file structure is:
Personal
--include
----main.h
--src
----main.cpp
----CMakeLists.txt
--CMakeLists.txt
CMakeLists.txt
# CMAKE version requirement
cmake_minimum_required(VERSION 3.12)
# Project name
project(scrap CXX)
# Configure the build
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_BUILD_TYPE Debug)
add_compile_options(-W -Wall -ggdb)
include_directories(include)
include_directories(${CMAKE_SOURCE_DIR}/include)
# What is being built
add_executable(scrap)
add_subdirectory(src)
# Add external dependencies
find_package(Threads REQUIRED)
target_link_libraries(scrap ${CMAKE_THREAD_LIBS_INIT})
src/CMakeLists.txt
# Add targets
target_sources(scrap PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
)
main.h
#ifndef PERSONAL_MAIN_H
#define PERSONAL_MAIN_H
#include <future>
#include <iostream>
#include <unistd.h>
class ScrapPaper
{
public:
ScrapPaper();
static void SpinUpThreads();
void ThreadFunction1(std::promise<bool> &prom);
void ThreadFunction2(std::promise<bool> &prom);
private:
};
#endif //PERSONAL_MAIN_H
main.cpp
#include "../include/main.h"
using namespace std;
void ScrapPaper::ThreadFunction1(promise<bool> &prom)
{
cout << "Thread " << this_thread::get_id() << " working in ThreadFunction1!" << endl;
sleep(10);
cout << "Thread " << this_thread::get_id() << " finished sleeping in Function1" << endl;
prom.set_value_at_thread_exit(true);
}
void ScrapPaper::ThreadFunction2(promise<bool> &prom)
{
cout << "Thread " << this_thread::get_id() << " working in ThreadFunction2!" << endl;
sleep(2);
cout << "Thread " << this_thread::get_id() << " finished sleeping in Function2" << endl;
prom.set_value_at_thread_exit(true);
}
void ScrapPaper::SpinUpThreads()
{
promise<bool> promise1;
future<bool> future1 = promise1.get_future();
std::thread (&ScrapPaper::ThreadFunction1, ref(promise1)).detach();
promise<bool> promise2;
future<bool> future2 = promise2.get_future();
std::thread (&ScrapPaper::ThreadFunction2, ref(promise2)).detach();
if (future1.get() && future2.get())
{
cout << "Everything was a-okay" << endl;
}
else
{
cout << "Whoops, there was an error..." << endl;
}
}
int main(int argc, char *argv[])
{
cout << "In Main..." << endl;
ScrapPaper::SpinUpThreads();
} // end main
Some of the errors that I am getting are:
error: no matching function for call to ‘std::thread::_Invoker<std::tuple<void (ScrapPaper::*)(std::promise<bool>&), std::reference_wrapper<std::promise<bool> > > >::_M_invoke(std::thread::_Invoker<std::tuple<void (ScrapPaper::*)(std::promise<bool>&), std::reference_wrapper<std::promise<bool> > > >::_Indices)’
operator()()
^~~~~~~~
and
error: no type named ‘type’ in ‘struct std::__invoke_result<void (ScrapPaper::*)(std::promise<bool>&), std::reference_wrapper<std::promise<bool> > >’
When the class is taken away and there is just a main()
and the ThreadFunction1(...)
and ThreadFunction2(...)
, the code builds and runs. Am I having a scope problem? Any advice or help is greatly appreciated!
Upvotes: 2
Views: 258
Reputation: 76305
You can do one of two things. As written, the two thread functions are non-static member functions. You must have an object to call them on, and that's what the other answers have addressed.
But neither of those functions uses any data from a ScrapPaper
object, so you can change them to static member functions and the rest of your code should work without changes. That is, change
class ScrapPaper
{
public:
ScrapPaper();
static void SpinUpThreads();
void ThreadFunction1(std::promise<bool> &prom);
void ThreadFunction2(std::promise<bool> &prom);
private:
};
to
class ScrapPaper
{
public:
ScrapPaper();
static void SpinUpThreads();
static void ThreadFunction1(std::promise<bool> &prom);
static void ThreadFunction2(std::promise<bool> &prom);
private:
};
Of course, with those changes, the natural question is why ScrapPaper
is a class, since it has no data and no object-specific behavior. That suggests possibly making ScrapPaper
a namespace rather than a class. But that's a subject for a different question.
Upvotes: 2
Reputation: 180594
The issue here is that since you are using member functions, you need an instance of the class to call the member functions on. If SpinUpThreads
wasn't static you could use
std::thread (&ScrapPaper::ThreadFunction1, this, ref(promise1)).detach();
std::thread (&ScrapPaper::ThreadFunction2, this, ref(promise2)).detach();
but since it is static you have to create an instance of the class to pass to thread
s constructor. You can share one object for both calls or give each thread it's own object. That woulds look like
ScrapPaper common;
std::thread (&ScrapPaper::ThreadFunction1, common, ref(promise1)).detach();
std::thread (&ScrapPaper::ThreadFunction2, common, ref(promise2)).detach();
//or
std::thread (&ScrapPaper::ThreadFunction1, ScrapPaper{}, ref(promise1)).detach();
std::thread (&ScrapPaper::ThreadFunction2, ScrapPaper{}, ref(promise2)).detach();
You can also use a lambda to make the call syntax easier. If you use a lambda you can write the function call in more natural manner and it would look like
ScrapPaper common;
std::thread ([&](){ common.ThreadFunction1(promise1); }).detach();
std::thread ([&](){ common.ThreadFunction2(promise2); }).detach();
//or
std::thread ([&](){ ScrapPaper{}.ThreadFunction1(promise1); }).detach();
std::thread ([&](){ ScrapPaper{}.ThreadFunction2(promise2); }).detach();
Upvotes: 2
Reputation: 62573
When using std::thread
to call the member function, the second argument should be an instance of the class (or the pointer to it).
In your case, the code would be
static ScrapPaper p;
std::thread (&ScrapPaper::ThreadFunction2, p, ref(promise2)).detach();
Upvotes: 2