Вызов шаблонной функции-члена с помощью 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 (на ride4fun.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
вы могли бы разыграть его тем временем: 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