Вывод аргумента шаблона для указателя на функцию-член

Я знаю, что есть много других подобных вопросов, но ни один из тех, на которые я смотрел, похоже, не относится к тому, что я делаю. Суть того, что у меня есть:

template <typename T>
void CallFn(T *p, void (T::*pfn)(void))
{
    (p->*pfn)();
}

вызывается с помощью:

class Foo
{
public:
    void Bar(void);
}
...
Foo *p = ...
CallFn(p, &Foo::Bar);

но это дает мне ошибку, говорящую, что компилятор не может вывести аргументы шаблона для указателя на функцию-член. Если вместо этого я использую такую ​​​​структуру:

template <typename T>
class Wrapper
{
public:
    void operator()(T *p, void (T::*pfn)(void))
    {
        (p->*pfn)();
    }
};
...
Foo *p = ...
Wrapper<Foo> x;
x(p, &Foo::Bar);

это работает, но синтаксис намного ужаснее. Мне просто интересно, почему компилятор может вывести тип функции-члена для класса, но не для функции.


person Duncan    schedule 19.06.2013    source источник
comment
Первый выглядит как потенциальный кандидат на SFINAE... Не могли бы вы показать нам, как вы вызываете эти два? Там может быть что-то другое в том, как вы это делаете   -  person K-ballo    schedule 19.06.2013
comment
Обновлено! Спасибо за отзыв, посмотрю еще немного   -  person Duncan    schedule 19.06.2013
comment
То, что вы показываете, отлично работает в нескольких компиляторах (например, ideone.com/fNh9X1). Это ваш настоящий код? Какой компилятор вы используете?   -  person K-ballo    schedule 19.06.2013
comment
Еще один вопрос, в вашем реальном коде это работает, если вы делаете CallFn<Foo>(p, &Foo::Bar);?   -  person K-ballo    schedule 19.06.2013
comment
Интересный. Я использую компилятор VC++ (v110). И да, вызов CallFn‹Foo›(...) действительно работает, спасибо! Немного разочаровывает, что мне приходится это делать, но это сработает.   -  person Duncan    schedule 19.06.2013
comment
Дункан: Вам не обязательно этого делать, ваш пример кода прекрасно работает и с VC++ (v110). Вы запускаете SFINAE в своем реальном использовании, вот что происходит, но я не могу вам больше сказать, если вы не покажете нам фактический код, который вызывает проблему.   -  person K-ballo    schedule 19.06.2013
comment
K-ballo: Хм, хорошо, спасибо. Код, который у меня есть сейчас, слишком раздут, чтобы публиковать его здесь. Я сократил его до того, что я опубликовал; единственная разница в том, что он использует тип WinRT (поэтому Foo ^ вместо Foo *), и это все еще не работает. Я посмотрю на это немного больше.   -  person Duncan    schedule 19.06.2013
comment
Конкретная ошибка: error C2784: 'void CallFn(T ^,void (__thiscall T::* )(void))' : could not deduce template argument for 'void (__thiscall T::* )(void)' from 'void (__cdecl Foo::* )(void)'   -  person Duncan    schedule 19.06.2013
comment
Обновление: я могу заставить его работать с типами, отличными от WinRT. Я сообщу об ошибке позже, предполагая, что это неправильная функциональность. Спасибо за вашу помощь!   -  person Duncan    schedule 19.06.2013
comment
@Duncan: То есть вы не только опубликовали вариант использования, в котором не было проблемы, но и указали неправильный язык? В любом случае, я не думаю, что это ошибка, не на любом из многих девиантных вариантов С++, которые есть у MSVC...   -  person K-ballo    schedule 19.06.2013
comment
C++/CX не должен так сильно отклоняться. Насколько я знаю, вывод типа шаблона должен работать так же, как и с vanilla C++. В любом случае, я посмотрю больше, является ли это ошибкой   -  person Duncan    schedule 19.06.2013
comment
Проблема в том, что параметр и аргумент имеют разные соглашения о вызовах: параметр имеет __thiscall (что правильно для функций-членов), а аргумент имеет __cdecl, который обычно используется для свободных/статических функций. Вы явно отмечаете функцию-член как __cdecl?   -  person Xeo    schedule 19.06.2013
comment
@Xeo Нет. Я даже могу явно объявить указатель функции с помощью __cdecl, и он все равно не удастся, но будет иметь __cdecl в качестве соглашения о вызовах для обоих указателей функций.   -  person Duncan    schedule 19.06.2013
comment
Кроме того, похоже, что это старая проблема без решения: deduction-with-a-ref-class-involved" rel="nofollow noreferrer">social.msdn.microsoft.com/Forums/windowsapps/en-US/   -  person Duncan    schedule 19.06.2013


Ответы (1)


Итак, похоже, здесь происходит несколько вещей. Во-первых, соглашение о вызовах неверно, и в PMF должно быть __cdecl. Во-вторых, после этого проблема все еще сохраняется. Это подтвержденная ошибка в компиляторе Visual Studio VC++.

person Duncan    schedule 20.06.2013