เรียกใช้ฟังก์ชันสมาชิกเทมเพลตด้วย std::async

เป็นไปได้และจะเรียกใช้ฟังก์ชันสมาชิกเทมเพลตของคลาสโดยใช้ std::async ได้อย่างไร (ควรไม่ใช้ std::bind) โปรดอธิบายว่ามาตรฐาน C++11 หรือ C++14 อนุญาตให้มีการเรียกโดยทั่วไปหรือไม่ และวิธีทำให้มันทำงานใน MSVS2013 โดยเฉพาะ

#include <future>

template<typename T> void non_member_template(T val) {}

struct X
{
    void member_non_template(int val) {}
    template<typename T> void member_template(T val) {}
    void call()
    {
        int val = 123;
        std::async(std::launch::async, &non_member_template<int>, val); // ok
        std::async(std::launch::async, &X::member_non_template, this, val); // ok
        std::async(std::launch::async, &X::member_template<int>, this, val); // error
    }
};

int main()
{
    X x;
    x.call();
}

person PowerGamer    schedule 16.01.2015    source แหล่งที่มา
comment
สิ่งนี้ควรคอมไพล์ ฉันไม่พบข้อผิดพลาดกับ gcc หรือ clang อาจเป็นข้อผิดพลาดใน MSVC   -  person 0x499602D2    schedule 16.01.2015
comment
@ 0x499602D2 คอมไพเลอร์ที่แตกต่างกันแสดงข้อความแสดงข้อผิดพลาดที่แตกต่างกันและเนื่องจากเทมเพลตเกี่ยวข้อง คอมไพเลอร์จึงยาวและเข้าใจยาก ฉันได้รับข้อผิดพลาดจาก MSVS2013 และ MSVS2015 (ที่ Rise4fun.com) และ GCC บางเวอร์ชันเมื่อเลือก C++14 ที่ ideone.com   -  person PowerGamer    schedule 16.01.2015
comment
เมื่อสร้างบน VS2013 ฉันได้รับข้อผิดพลาดนี้: MSB6006: "CL.exe" exited with code 1. และไม่มีข้อมูลอื่น ๆ   -  person derpface    schedule 16.01.2015
comment
คอมไพเลอร์ที่ทำงานบน Ideone ไม่รองรับการทำงานแบบมัลติเธรด ข้อผิดพลาดเป็นการอ้างอิงที่ไม่ได้กำหนด - ไม่เกี่ยวข้องกับเทมเพลต คุณจะเห็นว่ามีการคอมไพล์ที่นี่ อาจเป็นเพียงจุดบกพร่องในไลบรารีเธรดที่มาพร้อมกับ MSVC   -  person 0x499602D2    schedule 16.01.2015
comment
@ 0x499602D2 รายงานว่าเป็นข้อบกพร่องที่ connect.microsoft.com/VisualStudio/feedback/details/1090183 . มาดูกันว่า Microsoft พูดอะไรกับเรื่องนี้   -  person PowerGamer    schedule 16.01.2015
comment
คุณสามารถส่งมันได้ในระหว่างนี้: std::async(std::launch::async, (void(X::*)(int))&X::member_template<int>, this, val);   -  person Axalo    schedule 17.01.2015
comment
การหล่อก็เหมือนกับการใช้กำลังดุร้าย ในกรณีนี้ มันใช้กำลังรุนแรงยิ่งขึ้นเพราะคุณแนะนำให้นักแสดงสไตล์ C การใช้กำลังดุร้ายเมื่อคุณไม่เข้าใจบางสิ่งคือ... คุณคงเข้าใจ   -  person Ulrich Eckhardt    schedule 17.01.2015


คำตอบ (2)


ฉันไม่เคยเห็นโค้ดทำลายคอมไพเลอร์มาก่อน แต่เอาล่ะ:

ข้อผิดพลาด MSB6006: CL.exe ออกด้วยรหัส 1

ฉันขอแนะนำสิ่งเดียวกันกับ Axalo ในความคิดเห็นด้านบน คุณสามารถแก้ไขข้อผิดพลาดในการคอมไพล์ได้ด้วยการแคสต์

#include <future>

template<typename T> void non_member_template( T val ) {}

struct X
{
    void member_non_template( int val ) {}
    template<typename T> void member_template( T val ) {}
    void call()
    {
        int val = 123;
        std::async( std::launch::async,  &non_member_template<int>, val ); // ok
        std::async( std::launch::async, &X::member_non_template, this, val ); // ok
        //std::async( std::launch::async, &X::member_template<int>, this, val ); // error
        std::async( std::launch::async, static_cast< void ( X::* )( int )>( &X::member_template<int> ), this, val ); // ok
    }
};

int main()
{
    X x;
    x.call();
}
person sbsmith    schedule 17.01.2015

เห็นได้ชัดว่ามันเป็นข้อบกพร่องใน Microsoft Visual C++ 2013 และ 2015 Preview ซึ่งจะได้รับการแก้ไขใน Visual C++ เวอร์ชันอนาคต: การส่งผ่านฟังก์ชันเทมเพลตสมาชิกไปยัง std::async ทำให้เกิดข้อผิดพลาดในการคอมไพล์

ดังนั้นโปรแกรมตัวอย่างจึงเป็นรหัส C++ ที่ถูกต้อง และหากคุณต้องการวิธีแก้ปัญหาสำหรับ Visual C++ 2013 ให้ใช้การส่งครั้งสุดท้ายในการเรียก std::async ตามที่แนะนำในความคิดเห็น:

static_cast<void(X::*)(int)>(&X::member_template<int>)
person PowerGamer    schedule 31.01.2015