singlepost

template<class R,R f()> struct functor; << На главную или назад  

Третий день ломаю голову над задачкой указанной в теме. Хочется создавать тип-функтор передавая лишь указатель на функцию (не передавая возвращаемый тип), т.е. например так:

template<class R F()>
struct functor{
R operator()const{
return F()
};
};

int f();
char g();

typedef functor<&f> int_ftor;
typedef functor<&g> char_ftor;

Да, указав два параметра (как в теме) в шаблоне легко получить структуру-функтор для заданной функции, а вот одним лишь указателем на функцию не получается ситуацию разрулить.

std::ptr_fun позволяет получить функтор передавая лишь указатель на функцию, но он возвращает объект, а не тип.

Пробовал копать в сторону boost::function_traits – тоже не помогает.

Есть у кого какие идеи или trick'и как обойтись одним параметром?

Зачем нужно? Вот зачем: указатель на функцию в себе содержит достаточно информации о себе, и это позволяет вычислить даже возвращаемый тип. Таким образом передача дополнительного параметра шаблона кажется мне преступной роскошью от которой хотелось бы избавиться.

27 ответов в теме “template<class R,R f()> struct functor;”

  1. 27
    Павел Потапов ответил:

    Ну… я просто подумал, что раз интересует вариант только для функций без параметров, то задача достаточно локальная. Думаю, что для решения этой задачи в глобальном масштабе потребуется написать не один десяток шаблонов.

  2. 26
    Дмитрий Потапов ответил:

    >Вы используете в конечной программе бесконечное число типов C++?
    А вы используете единожды написанный код только в одной программе? Каждый раз пишете весь код индивидуально под задачу?

  3. 25
    Павел Потапов ответил:

    Мое дело предложить…

    > "для каждого возвращаемого значения функтора сделать "шорткат"" не получится, ибо типов в С++ бесконечное число.

    и опять же, надо приводить цитаты полностью:
    "Если типов возвращаемых значений немного, то в качестве частичного решения поставленной задачи могу предложить такое"

    ЗЫ Неужели Вы используете в конечной программе бесконечное число типов C++?

  4. 24
    Дмитрий Потапов ответил:

    брутфорс до добра ещё никого не доводил,
    "для каждого возвращаемого значения функтора сделать "шорткат"" не получится, ибо типов в С++ бесконечное число.

  5. 23
    Павел Потапов ответил:

    Полчаса размышлений и игры с компилером привели к следующему пониманию проблемы…

    Думаю, что все заинтересованные в этой задаче знают, что шаблонными параметрами могут быть 2 вида сущностей: типы и константы конкретных типов.

    В интересующем нас случае "template<class R,R f()> struct functor;" представлены оба параметра: class R – тип, R f() – константа типа "R ()". Без класса R обойтись не удастся, т.к. без него будет невозможно задать тип константы. А переменных без типа плюсовый компилер не понимает.

    Если типов возвращаемых значений немного, то в качестве частичного решения поставленной задачи могу предложить такое:

    template<class R,R f()> struct functor
    {
    R operator()() const
    {
    return f();
    }
    };

    template<int f()> struct ifunctor : functor<int, f> {};

    int g();

    typedef ifunctor<g> igfunctor;

    Т.е. для каждого возвращаемого значения функтора сделать "шорткат".

  6. 22
    Жека Кирпичев ответил:

    Эх, ну тогда зря удалили, значит.
    (Кстати, внутри темы мог удалить и сам автор темы.)

  7. 21
    Дмитрий Потапов ответил:

    >Хм, в пространственных структурах точно не я. А что ты там писал?
    Сказал что человека на гугле забанили, и что вики по первому же запросу десяток результатов выдаёт.
    Вообще без оскорблений и прочего.

  8. 20
    Дмитрий Потапов ответил:

    >>А вот читать в свой адрес оскорбления и необоснованные претензии мне не очень нравится.
    Были бы оскорбления – мой пост удалили бы.
    А так я никаких оскорблений не припомню.

  9. 19
    Павел Потапов ответил:

    >>В противном случае, компилятору не удается угадать Ваши желания
    >Ещё как удаётся. Пример тому std::ptr_fun который создаёт объект pointer_to_unary_function передавая отдельно тип возвращаемого значение, отдельно тип параметра.

    Если уж цитировать, то до конца… а дальше я писал как раз то, что Вы приводите в пример, а именно:

    "Автоматически он умеет только определять параметры шаблонной функции. Да и то не всегда."

    О чем, кстати, написано в стандарте. Вам найти и привести цитату или поверите?

    > Смею заметить что вызываю я именно функцию, а не структуру, и поведение зависит лишь от возвращаемого значения.

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

    > Впрочем я и не заставляю никого этот trick юзать, всего лишь пример для того чтобы показать что функция может быть параметром шаблона, факт который вы столь уверенно отрицали.

    Ошибки бывают у всех, кроме Вас (признаю). То, что функция может быть параметром шаблона, я знаю. Лично у меня вызвало вопрос использование именно УКАЗАТЕЛЯ на функцию, что на мой взгляд редко имеет смысл в шаблонах. Проще использовать именно саму функцию.

    Далее, я удосужился проверить свое предположение и принести извинения.

    А вот читать в свой адрес оскорбления и необоснованные претензии мне не очень нравится.

  10. 18
    Жека Кирпичев ответил:

    Хм, в пространственных структурах точно не я. А что ты там писал?

  11. 17
    Дмитрий Потапов ответил:

    Ну ладно не шесть, четыре – два в "Хочу написать игру" и два в "Пространственные структуры данных", за два дня не так уж мало. А что делать, из группы исключить меня уже никто не сможет :-)

  12. 16
    Жека Кирпичев ответил:

    Да полно тебе, Дмитрий, не шесть, а одно или два. Зато, видимо, *очень* дорогих твоему сердцу ;)
    (Хотя возможно, что еще что-нибудь похерили другие модераторы)

  13. 15
    Дмитрий Потапов ответил:

    >Попрошу без оскорблений.
    Где ж тут оскорбление? Нету никакого оскорбления, модератор уже и так за последние два дня штук шесть моих сообщений похерил, так что лишнего повода я ему не даю.

    >В противном случае, компилятору не удается угадать Ваши желания
    Ещё как удаётся. Пример тому std::ptr_fun который создаёт объект pointer_to_unary_function передавая отдельно тип возвращаемого значение, отдельно тип параметра.

    >Смею заметить, что в данном случае используется структура, а не функция.
    Смею заметить что вызываю я именно функцию, а не структуру, и поведение зависит лишь от возвращаемого значения.
    Впрочем я и не заставляю никого этот trick юзать, всего лишь пример для того чтобы показать что функция может быть параметром шаблона, факт который вы столь уверенно отрицали.

    >Кстати, вдогонку. Вот такая вещь не работает, т.к. это структуры двух разных типов:
    >functor<int, f> ftor = functor<int, f1>();

    И? Каков логический вывод? То что вы присваивать объёкты разных типов нельзя просто так? Спасибо, я это и так знал. Слив незащитан.

  14. 14
    Павел Потапов ответил:

    > Ну вот, выискался ещё один гигант мысли… третий уже.

    Попрошу без оскорблений.

    > Идите и прочтите внимательнее всё что было тут высказано до вашего опуса, а затем ещё Александреску на ночь, чтобы стыдно стало.

    Стыдно должно быть Вам, так как вам должно быть известно, что для того, чтобы описать функцию надо указать типы входных и выходных параметров. А раз Вы в шаблоне используете шаблонное возвращаемое значение, то вы должны это указать. И именно этого он от Вас и ждет в данном случа. В противном случае, компилятору не удается угадать Ваши желания. Автоматически он умеет только определять параметры шаблонной функции. Да и то не всегда.

    > И функцию можно в параметр шаблона передать и по возвращаемому значению можно перегрузить (и даже проще чем у меня можно).

    Смею заметить, что в данном случае используется структура, а не функция. И именно функции по возвращаемому значению перегрузить нельзя. Так что не стоит говорить, что азбучная истина неверна, если Вы не понимаете о чем она говорит.

    > И советую не говорить человеку о том что он не прав если не можете это подкрепить цитатой из стандарта.

    взаимно

    —-

    Кстати, вдогонку. Вот такая вещь не работает, т.к. это структуры двух разных типов:
    functor<int, f> ftor = functor<int, f1>();

    ЗЫ Хотел помочь, но в данном контексте не вижу смысла этого делать.

  15. 13
    Павел Потапов ответил:

    Проверил. С указателями на функцию оно все-таки компилится. Беру свои слова про константы назад.

  16. 12
    Дмитрий Потапов ответил:

    >&f – константа времени выполнения, а в параметрах шаблона могут быть только константы времени компиляции

    Ну вот, выискался ещё один гигант мысли… третий уже.
    Снова будут мне внушать "азбучные" истины… параметром шаблона функция быть не может… нельзя перегрузить функцию только по возвращаемому значению… прочая лабуда…
    Да можно это всё! Читать внимательнее нужно то что пишут другие, а вы даже мой первый пост не удосужились толком прочитать.
    Идите и прочтите внимательнее всё что было тут высказано до вашего опуса, а затем ещё Александреску на ночь, чтобы стыдно стало.
    А вот вам затравка, что всё можно, даже то чего нельзя:

    #include <iostream>
    using namespace std;

    char f_char()
    {cout<<"f_char() called\n";return char();}

    int f_int()
    {cout<<"f_int() called\n";return int();}

    template<class R1,R1 f1(),class R2,R2 f2()>
    struct proxy
    {
    operator R1()const
    {return f1();}
    operator R2()const
    {return f2();}
    };

    proxy<char,&f_char,int,&f_int> f()
    {return proxy<char,&f_char,int,&f_int>();}

    int main(int argc,char* argv[])
    {
    char a=f();// печатает f_char() called
    int b=f();// печатает f_int() called
    return 0;
    }

    Компилится экспресс студией 2008 на ура. (ГЦЦ наверняка тоже соберёт, просто под кубунтой у меня инет не настроен). И функцию можно в параметр шаблона передать и по возвращаемому значению можно перегрузить (и даже проще чем у меня можно).
    И советую не говорить человеку о том что он не прав если не можете это подкрепить цитатой из стандарта.

  17. 11
    Павел Потапов ответил:

    > typedef functor<&f> int_ftor;
    > typedef functor<&g> char_ftor;

    Компилятор такое не съест. &f – константа времени выполнения, а в параметрах шаблона могут быть только константы времени компиляции.

    Тут

    > template<class R F()>
    > struct functor{
    > R operator()const{
    > return F()
    > };
    > };

    используется не указатель на функцию, а сама функция. Если бы был указатель, то вызов был бы немного другой:
    return (*F)();

  18. 10
    Жека Кирпичев ответил:

    О, блин, точно. Надо вспоминать C++ :-|

  19. 9
    Дмитрий Потапов ответил:

    >допустимые типы аргументов шаблонов не включают в себя указатели на функции
    Ещё как включают. Не стоит писать того чего не знаешь точно.

  20. 8
    Жека Кирпичев ответил:

    Да, и впрямь прочитал невнимательно.
    (В языке Scala для несколько похожей цели придумали "self types")

    Полагаю, что именно в таком виде – functor<&f> – это невозможно, поскольку допустимые типы аргументов шаблонов не включают в себя указатели на функции; впрочем, это ты, наверное, и без меня знаешь.

    Можно было бы сделать такой класс fun_traits, что если бы выражение
    typedef fun_traits(&f)::type int_callback;
    компилилось, то оно делало бы то, что надо :) Но похоже, что typedef такого не умеет.

    (

    Собственно, примитивный подходящий fun_traits выглядел бы так:
    template <class F>
    struct fun_traits {};

    template <>
    struct fun_traits<int (*)()> {
    fun_traits(int (*f)()) {}
    typedef int (*type)();
    };

    )

    Может, это, по крайней мере, подтолкнет к решению.

  21. 7
    Дмитрий Потапов ответил:

    2: Дмитрий lnk~ Матвеев
    > 2 Александр Sapiens Ленков
    > Я? Вы меня знаете?? О_О
    Саша обращался ко мне :-)

    >не так уж оно и накладно имхо
    не накладно если у вас таких параметров один-два, а если составляете mpl::list параметров эдак из десяти, то несколько утомляет.

    2: Жека jkff Кирпичев
    Нет.
    Как ты предполагаешь в "это" передавать указатель на функцию?
    При попытке это сделать, твоё творение просто не скомпилится.
    typedef Functor<&g> g_ftor; // не помпилится потому что бред
    Прочитай мой первый пост внимательнее

  22. 6
    Жека Кирпичев ответил:

    template <class PF>
    struct Functor {
    PF pf_;
    Functor (PF pf) :pf_(pf) {}
    function1_traits<PF>::result_type operator(function1_traits<PF>::arg_type arg) const {
    return pf(arg);
    }
    };

    Написать подходящий function1_traits вроде несложно.
    Это то, что ты имеешь в виду?

  23. 5
    Дмитрий Матвеев ответил:

    2 Дмитрий analizer Потапов
    Посмотрел в Modern C++ Design – и правда что то я гоню, там тип возвращаемого значения задаётся явно при каждом объявлении функтора

    хммм… сдаётся мне что так и придется передавать тип возвращаемого значения как шаблонный аргумент, не так уж оно и накладно имхо =))))

    2 Александр Sapiens Ленков
    Я? Вы меня знаете?? О_О

  24. 4
    Дмитрий Потапов ответил:

    2: Дмитрий lnk~ Матвеев
    А можно линку на то где он это реализовал? А то в Modern C++ Design я такого не видел, а финт как с sizeof тут не подходит. Было бы очень интересно глянуть.

    2: Алексей Гончар
    Читайте классиков, как например, г-н Матвеев. Я говорил не о том как это реализуется в откомплированном коде (асм я и сам знаю), а о том как заставить компилятор понять то что я написал до того как соберётся объектник.

  25. 3
    Александр Ленков ответил:

    Дима. из тебя до сих пор креатив прет – не читайте перед английским иностранные газеты :) )))

  26. 2
    Дмитрий Матвеев ответил:

    Александреску уже всё давно показал и реализовал.

  27. 1
    Алексей Гончар ответил:

    Указатель на ф-ю не содержит информации о возвращаемом параметре о_О Откуда ты это вычитал?Указатель на ф-ю – адрес начала кода этой ф-ии в адресном пространстве процесса. А возвращаемое значение ф-я записывается в определенныйрегистр и впоследствии это значение забирается оттуда вызывающей стороной.
    Поэтому тебе в любом случае придется передавать тип возвращаемого значения)))

Клуб программистов работает уже ой-ой-ой сколько, а если поточнее, то с 2007 года.