在lambda中传递参数时无法调用指向成员的指针

时间:2018-03-09 01:09:33

标签: c++ stdthread

我正在尝试为std :: thread创建一个包装器,它允许我查看在被调用的线程上抛出了哪些异常。当一个线程被连接时,我将它们传播。这在使用参数调用函数或不带参数的类成员函数时工作正常。但是,如果我尝试使用带有参数的类成员函数,我会收到一个错误,我无法理解。下面是一些示例代码,可以重现我所看到的问题。

#include <iostream>
#include <string>

#include <thread>
#include <exception>
#include <utility>

class BlazingThread {
public:
    template< typename Function, typename... Args >
    explicit BlazingThread( Function&& f, Args&&... args ){
        exception = nullptr;
        thread = std::thread(([&](){
            try{
                auto caller = std::forward<Function>(f);

                caller(args...);
            }catch(...){
                //non handled exception rethrow so we can stop whoever started this mess
                //exception = std::make_exception_ptr(BlazingException("An unknown error occurred!"));
            }

        }));

    }

    template< typename Function >
    explicit BlazingThread( Function&& f){
        exception = nullptr;
        thread = std::thread(([&](){
            try{
                //std::bind(f);
                std::forward<Function>(f);

            }catch(...){
                //non handled exception rethrow so we can stop whoever started this mess
            //  exception = std::make_exception_ptr(BlazingException("An unknown error occurred!"));
            }

        }));

    }

    BlazingThread(BlazingThread && other){
        this->thread = std::move(other.thread);
        this->exception = std::move(other.exception);
    }

    BlazingThread(){

    }

    BlazingThread& operator=(const BlazingThread&) = delete;
    BlazingThread& operator=(BlazingThread && other){
        this->thread = std::move(other.thread);
        this->exception = std::move(other.exception);
        return *this;
    }
    BlazingThread(const BlazingThread& other) = delete;
    virtual ~BlazingThread();

    void join();
    static unsigned int hardware_concurrency(){
        return std::thread::hardware_concurrency();
    }
private:
    std::thread thread;
    std::exception_ptr exception;
};





void BlazingThread::join(){
    thread.join();
    if(this->exception != nullptr){
        //an exception was thrown in the thread, lets rethrow it
        std::rethrow_exception(this->exception);
    }
}

BlazingThread::~BlazingThread() {
    // TODO Auto-generated destructor stub
}





void testFunction(int x, int y){
    int z = x + y;
    std::cout<<"x + y = "<<z<<std::endl;
    //throw BlazingException("A planned error!");
}

class TestClass{
public:
    TestClass(int newX){
        this->x = newX;
    }

    void talk(){
        std::cout<<"this is "<<x<<std::endl;
    }
    void talking(){

        BlazingThread thread2(&TestClass::talk);
        thread2.join();
        std::string msg = "something else ";
        BlazingThread thread3(&TestClass::talkSomething, msg);
        thread3.join();



    }

    void talkSomething(std::string testMsg){
        std::cout<<testMsg<<x<<std::endl;
    }
private:
    int x;
};

int main() {
    try{
        TestClass test(3);
        test.talk();

        BlazingThread thread(testFunction,2,4);

        thread.join();
    }catch(...){
        //std::cout<<"Found BlazingException, what = "<<e.what()<<std::endl;
    }
    return 0;
}

    BlazingThread thread3(&TestClass::talkSomething, msg);
    thread3.join();

防止编译。我看到的错误是

/usr/include/c++/5/functional: In instantiation of ‘struct std::_Bind_check_arity<void (TestClass::*)(std::__cxx11::basic_string<char>), std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>’:
    /usr/include/c++/5/functional:1439:12:   required from ‘struct std::_Bind_helper<false, void (TestClass::*)(std::__cxx11::basic_string<char>), std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>’
    /usr/include/c++/5/functional:1462:5:   required by substitution of ‘template<class _Func, class ... _BoundArgs> typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...) [with _Func = void (TestClass::*)(std::__cxx11::basic_string<char>); _BoundArgs = {std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&}]’
    ../src/simple-thread.cpp:24:34:   required from ‘BlazingThread::BlazingThread(Function&&, Args&& ...)::<lambda()> [with Function = void (TestClass::*)(std::__cxx11::basic_string<char>); Args = {std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&}]’
    ../src/simple-thread.cpp:24:80:   required from ‘struct BlazingThread::BlazingThread(Function&&, Args&& ...) [with Function = void (TestClass::*)(std::__cxx11::basic_string<char>); Args = {std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&}]::<lambda()>’
    ../src/simple-thread.cpp:21:10:   required from ‘BlazingThread::BlazingThread(Function&&, Args&& ...) [with Function = void (TestClass::*)(std::__cxx11::basic_string<char>); Args = {std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&}]’
    ../src/simple-thread.cpp:121:55:   required from here
    /usr/include/c++/5/functional:1426:7: error: static assertion failed: Wrong number of arguments for pointer-to-member
           static_assert(_Varargs::value
           ^

下面是我需要修复它的工作版本,以便它需要std :: ref来引用像std :: thread吗

    #include <iostream>
    #include <string>

    #include <thread>
    #include <exception>
    #include <utility>

    class BlazingThread {
    public:




        template< typename Function, typename... Args >
        explicit BlazingThread( Function&& f, Args&&... args ){
            exception = nullptr;

            thread = std::thread(([&f,args...](){
                try{
                    //auto caller = std::forward<Function>(f);

                    //caller(std::forward<Args>(args)...);
                    auto functionCall = std::bind(std::forward<Function>(f),args...);
                    functionCall();
                }catch(...){
                    //non handled exception rethrow so we can stop whoever started this mess
                    //exception = std::make_exception_ptr(BlazingException("An unknown error occurred!"));
                }

            }));

        }

        template< typename Function >
        explicit BlazingThread( Function&& f){
            exception = nullptr;
            thread = std::thread(([&](){
                try{
                    //std::bind(f);
                    std::forward<Function>(f)();

                }catch(...){
                    //non handled exception rethrow so we can stop whoever started this mess
                //  exception = std::make_exception_ptr(BlazingException("An unknown error occurred!"));
                }

            }));

        }

        BlazingThread(BlazingThread && other){
            this->thread = std::move(other.thread);
            this->exception = std::move(other.exception);
        }

        BlazingThread(){

        }

        BlazingThread& operator=(const BlazingThread&) = delete;
        BlazingThread& operator=(BlazingThread && other){
            this->thread = std::move(other.thread);
            this->exception = std::move(other.exception);
            return *this;
        }
        BlazingThread(const BlazingThread& other) = delete;
        virtual ~BlazingThread();

        void join();
        static unsigned int hardware_concurrency(){
            return std::thread::hardware_concurrency();
        }
    private:
        std::thread thread;
        std::exception_ptr exception;
    };





    void BlazingThread::join(){
        thread.join();
        if(this->exception != nullptr){
            //an exception was thrown in the thread, lets rethrow it
            std::rethrow_exception(this->exception);
        }
    }

    BlazingThread::~BlazingThread() {
        // TODO Auto-generated destructor stub
    }


    void testFunction(){
        std::cout<<"tester"<<std::endl;
        //throw BlazingException("A planned error!");
    }


    void testFunction2(int x, int y){
        int z = x + y;
        std::cout<<"x + y = "<<z<<std::endl;
        //throw BlazingException("A planned error!");
    }

    class TestClass{
    public:
        TestClass(int newX){
            this->x = newX;
        }

        void talk(){
            std::cout<<"this is "<<x<<std::endl;
        }
        void talking(){

            BlazingThread thread2(&TestClass::talk,this);
            thread2.join();
            std::string msg = "something else ";
            BlazingThread thread3(&TestClass::talkSomething,this, msg);
            thread3.join();



        }

        void talkSomething(std::string testMsg){
            std::cout<<testMsg<<x<<std::endl;
        }
    private:
        int x;
    };

    int main() {
        try{
            TestClass test(3);
            test.talking();

            BlazingThread thread(testFunction2,2,4);

            thread.join();
            BlazingThread thread2(testFunction);

            thread2.join();
        }catch(...){
            //std::cout<<"Found BlazingException, what = "<<e.what()<<std::endl;
        }
        return 0;
    }

1 个答案:

答案 0 :(得分:2)

更改

BlazingThread thread2(&TestClass::talk);

BlazingThread thread2(&TestClass::talk, this);

和类似的eslewhere。您需要传递该对象才能继续工作。

当lambda超出当前范围时(与将其传递给std线程时一样),也停止使用[&]捕获。但这只是一个运行时错误。