Вывод сигнатуры функции

Тема в разделе "LANGS.C", создана пользователем _DEN_, 26 янв 2010.

  1. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    Не помню, возможна эта тема уже обсуждалась...

    Код (Text):
    1. void helper()
    2. {
    3. }
    4.  
    5. struct foo
    6. {
    7.     void bar() {}
    8. };
    9.  
    10. template <class T, class F>
    11. void check(F T::*)
    12. {
    13.     F* ptr = &helper;
    14. }
    15.  
    16. int main()
    17. {
    18.     check(&foo::bar);
    19.     return 0;
    20. }
    В камю, как и ожидается, это компилируется. Микрософт (2005-2008 SP1) компилито не хочет, говоря

    Как следствие - не верно цепляются частичные шаблонные специализации, параметризованные сигнатурой, выведенной шаблонной функцией. Видимо микрософт считает, что конвенция вызрва входит в сигнатуру. Есть мысли насчет воркэраунда?
     
  2. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    _DEN_
    используй boost.function_traits для анализа и синтеза типа
     
  3. RedLord

    RedLord Member

    Публикаций:
    0
    Регистрация:
    23 июн 2005
    Сообщения:
    183
    Адрес:
    Ukraine
    _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;
    }
     
  4. RedLord

    RedLord Member

    Публикаций:
    0
    Регистрация:
    23 июн 2005
    Сообщения:
    183
    Адрес:
    Ukraine
    _DEN_

    для 2008 не подойдет
     
  5. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    В VS 2010 beta2 ещё хуже:
    Явный баг.
     
  6. RedLord

    RedLord Member

    Публикаций:
    0
    Регистрация:
    23 июн 2005
    Сообщения:
    183
    Адрес:
    Ukraine
    green
    в 2010 приведенный код работает
     
  7. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    RedLord
    Да, ваш код работает.
     
  8. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    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;
    }
     
  9. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    И правильно делает. Как можно вызывать функции с разной конвенцией вызова?
     
  10. nop_

    nop_ New Member

    Публикаций:
    0
    Регистрация:
    21 июн 2007
    Сообщения:
    61
    Код (Text):
    1. F* ptr = &helper;
    Типы 'ptr' и выражения '&helper' совпадают и равны 'void(*)(void)', поэтому никакой ошибки здесь быть не должно. Понятие 'конвенции вызова' как таковой в стандарте отсутствует, но раз компилятор все же использует что-то специфическое, то его разработчики могли бы позаботиться о том, чтобы компиляция приведенного кода не приводила к ошибке. Как минимум можно не протаскивать конвенцию вызова из выведенного типа 'F T::*' в тип 'F' как это сейчас происходит:

    Код (Text):
    1. template <class T, class F>
    2. void check(F T::* x)
    3. {
    4.   std::cout << typeid(F*).name() << std::endl;
    5.   std::cout << typeid(x).name() << std::endl;
    6.   std::cout << typeid(&helper).name() << std::endl;
    7.   std::cout << typeid(void(*)()).name() << std::endl;
    8. }
     
  11. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    GoldFinch

    Да это-то понятно. Тут интересно было разобраться в языке. Так-то самую верхнюю задачу можно решить бустом вообще без дополнительных телодвижений.

    nop_
    [​IMG]

    J0E
    [​IMG]
     
  12. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    :)

    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);
    }
     
  13. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Здесь согласен, я тупанул, не разобравшись что делает DEN
    Здесь не согласен. Мой вопрос остается в силе, поставь себя на место разработчиков, как бы ты разрулил ситуацию с вызовом таких одинаковых сигнатур через указатель?
    void (__cdecl*)(int)
    void (__stdcall*)(int)

    Обрати внимани е на разницу
    (T::*)() // явно указывает что это функция, T дедуцируется в тип класса и компилируется.
    T::* // а кокой тип у Т здесь? поэтому при дедукции T прицепляется заодно и конвенция вызова, по умолчанию у членов она thiscall

    оригинальный вариант с /Gz вообще вызывает ICE у ВЦ 2005 )
     
  14. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    F пропустил выше но сути это не меняет
     
  15. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    J0E

    Все очень просто. Поскольку в стандарте ничего не сказано про конвенции вызова, то введение их в язык в качестве расширения - добровольно взятый на себя геморой, который микрософты не удосужились корректно разрулить. Можно ввести в компилятор любые расширения, но код, находящийся в рамках стандарта, от этого ломаться не должен.
     
  16. nop_

    nop_ New Member

    Публикаций:
    0
    Регистрация:
    21 июн 2007
    Сообщения:
    61
    у 'T' - 'foo', абсолютно такой же как и в случае со скобками. 'F' имеет тип 'void(void)' или просто 'void()' - это так называемый 'function type'. Объект ('ptr'), определенный как указатель на такой тип сам по себе имеет тип void(*)(). Здесь никакой информации о принадлежности к 'foo' нет, т.к. это тип ('ptr' а не тип параметра) обычного указатель на non-member функцию.

    А вот типом 'F T::*' действительно является pointer-to-member, и он не может быть легально преобразован к 'void(*)()'. Но исходная проблема-то возникает не здесь (тем более параметр 'check' безымянный), а при инициализации 'F* ptr = &helper;'
     
  17. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Конвенции вызовов сложились исторически до стандарта, это вынужденная мера. Ругать кого-то за несделанное не предлагая и не прилогая усилия к решению называется нытье ;)
    Исходная проблема возникает как раз здесь, присвоение невозможно изза проблем с типом F, посмотри №12 который компилируется.
     
  18. nop_

    nop_ New Member

    Публикаций:
    0
    Регистрация:
    21 июн 2007
    Сообщения:
    61
    Я думал что смайлик там по делу стоял... 'F' твоем примере выводится в 'void', и указатель на функцию (&helper) успешно приводится к 'void*'. 'F (T::*)()' это далеко не одно и тоже, что и 'F T::*'.
     
  19. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    J0E

    Это проблема конвенций и истории, а не стандарта.

    Это проблема разработчиков компилятора. В камю ее нет.

    А, то есть я сам должен дописать в микрософтовском компиляторе, чего там ему не хватает, верно, Кэп? :))))))))))))))))
    Давай попробуем по-простому :) Есть стандарт. Есть компилятор. Одна из задача компилятора - поддержать стандарт. Компилятор стандарт не поддерживает. Следовательно, с задачей компилятор не справился. Пока что все верно?
     
  20. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Мой смайлик по делу, потому что влез в топик экстрасенсов ) Почему бы не сказать что хотят получить, если не устраивает ответ №2, или ответ 10 где F выводится правильным типом?

    Зачем делать
    void(*ptr)() = &foo::bar;