Не помню, возможна эта тема уже обсуждалась... Код (Text): void helper() { } struct foo { void bar() {} }; template <class T, class F> void check(F T::*) { F* ptr = &helper; } int main() { check(&foo::bar); return 0; } В камю, как и ожидается, это компилируется. Микрософт (2005-2008 SP1) компилито не хочет, говоря Как следствие - не верно цепляются частичные шаблонные специализации, параметризованные сигнатурой, выведенной шаблонной функцией. Видимо микрософт считает, что конвенция вызрва входит в сигнатуру. Есть мысли насчет воркэраунда?
_DEN_ под рукой 2008 студии нет, но попробуй template <class Ty> struct MemFnHelper; template <class F, class Ty> struct MemFnHelper<F Ty::*> { typedef F type; }; template <class F> void check(F) { MemFnHelper<F>::type* x = &helper; } int main() { check(&foo::bar); return 0; }
void __stdcall helper() { } struct foo { void __stdcall bar() {} }; template <class T, class F> void check(F T::*) { F* ptr = &helper; } int main() { check(&foo::bar); return 0; }
Код (Text): F* ptr = &helper; Типы 'ptr' и выражения '&helper' совпадают и равны 'void(*)(void)', поэтому никакой ошибки здесь быть не должно. Понятие 'конвенции вызова' как таковой в стандарте отсутствует, но раз компилятор все же использует что-то специфическое, то его разработчики могли бы позаботиться о том, чтобы компиляция приведенного кода не приводила к ошибке. Как минимум можно не протаскивать конвенцию вызова из выведенного типа 'F T::*' в тип 'F' как это сейчас происходит: Код (Text): template <class T, class F> void check(F T::* x) { std::cout << typeid(F*).name() << std::endl; std::cout << typeid(x).name() << std::endl; std::cout << typeid(&helper).name() << std::endl; std::cout << typeid(void(*)()).name() << std::endl; }
GoldFinch Да это-то понятно. Тут интересно было разобраться в языке. Так-то самую верхнюю задачу можно решить бустом вообще без дополнительных телодвижений. nop_ J0E
void helper() { } struct foo { void bar() {} }; template <class T, class F> void check(F (T::*)()) { F* ptr = &helper; // warning C4189: 'ptr' : local variable is initialized but not referenced } int main() { check(&foo::bar); }
Здесь согласен, я тупанул, не разобравшись что делает DEN Здесь не согласен. Мой вопрос остается в силе, поставь себя на место разработчиков, как бы ты разрулил ситуацию с вызовом таких одинаковых сигнатур через указатель? void (__cdecl*)(int) void (__stdcall*)(int) Обрати внимани е на разницу (T::*)() // явно указывает что это функция, T дедуцируется в тип класса и компилируется. T::* // а кокой тип у Т здесь? поэтому при дедукции T прицепляется заодно и конвенция вызова, по умолчанию у членов она thiscall оригинальный вариант с /Gz вообще вызывает ICE у ВЦ 2005 )
J0E Все очень просто. Поскольку в стандарте ничего не сказано про конвенции вызова, то введение их в язык в качестве расширения - добровольно взятый на себя геморой, который микрософты не удосужились корректно разрулить. Можно ввести в компилятор любые расширения, но код, находящийся в рамках стандарта, от этого ломаться не должен.
у 'T' - 'foo', абсолютно такой же как и в случае со скобками. 'F' имеет тип 'void(void)' или просто 'void()' - это так называемый 'function type'. Объект ('ptr'), определенный как указатель на такой тип сам по себе имеет тип void(*)(). Здесь никакой информации о принадлежности к 'foo' нет, т.к. это тип ('ptr' а не тип параметра) обычного указатель на non-member функцию. А вот типом 'F T::*' действительно является pointer-to-member, и он не может быть легально преобразован к 'void(*)()'. Но исходная проблема-то возникает не здесь (тем более параметр 'check' безымянный), а при инициализации 'F* ptr = &helper;'
Конвенции вызовов сложились исторически до стандарта, это вынужденная мера. Ругать кого-то за несделанное не предлагая и не прилогая усилия к решению называется нытье Исходная проблема возникает как раз здесь, присвоение невозможно изза проблем с типом F, посмотри №12 который компилируется.
Я думал что смайлик там по делу стоял... 'F' твоем примере выводится в 'void', и указатель на функцию (&helper) успешно приводится к 'void*'. 'F (T::*)()' это далеко не одно и тоже, что и 'F T::*'.
J0E Это проблема конвенций и истории, а не стандарта. Это проблема разработчиков компилятора. В камю ее нет. А, то есть я сам должен дописать в микрософтовском компиляторе, чего там ему не хватает, верно, Кэп? ))))))))))))))) Давай попробуем по-простому Есть стандарт. Есть компилятор. Одна из задача компилятора - поддержать стандарт. Компилятор стандарт не поддерживает. Следовательно, с задачей компилятор не справился. Пока что все верно?
Мой смайлик по делу, потому что влез в топик экстрасенсов ) Почему бы не сказать что хотят получить, если не устраивает ответ №2, или ответ 10 где F выводится правильным типом? Зачем делать void(*ptr)() = &foo::bar;