LINUX.ORG.RU

Параметризовать шаблон шаблоном функции

 


0

3

Параметризовать шаблон шаблоном класса понятно как:

template<template<class> class T> class Foo { /* ...*/ };

А параметризовать шаблоном функции? Вроде этого (код не компилируется):

template<template<class R, class A> R (*fun)(A)> class Foo { /* ...*/ };

Если это возможно, то как? Если нет, то где в документации об этом сказано?

★★★★★

Ты можешь параметризовать либо переменной, либо именем типа, либо именем шаблона типа (твой первый пример). Сказано об этом в самом начале 14.1 (temp.param) N3337, параграфы 1-8.

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 4)
Ответ на: комментарий от yoghurt

У меня была такая мысль, но я не осилил сделать function<R (A)>из R my_func<A> (кроме как макросом, но это очевидное мошенничество). Можешь дать пример?

tailgunner ★★★★★
() автор топика
Ответ на: комментарий от tailgunner

у меня кстати и без std::function сработало:

#include <string>
#include <functional>
#include <typeinfo>
#include <iostream>

template<class> struct Test;

template<class R, class A>
struct Test<R(A)>
{
    Test()
    {
        std::cout << typeid(A).name()
                  << " -> "
                  << typeid(R).name()
                  << std::endl;
    }
};

bool        foo(int x) { return x > 0; }
float       bar(int x) { return 1.f/x; }
std::string baz(int x) { return std::to_string(x); }

int main(int argc, char *argv[])
{
    Test<decltype(foo)>();
    Test<decltype(bar)>();
    Test<decltype(baz)>();
}

yoghurt ★★★★★
()
Ответ на: комментарий от yoghurt

Наверное, я мутно выразился, но твой пример - точно не то, что мне нужно. У тебя foo, bar, baz - функции, а мне нужно, чтобы они были шаблонами функций.

tailgunner ★★★★★
() автор топика
Ответ на: комментарий от tailgunner

а ты какую задачу-то глобально хочешь решить? Я пока контекст слабо понимаю, в каком оно будет использоваться

yoghurt ★★★★★
()
Ответ на: комментарий от yoghurt

а ты какую задачу-то глобально хочешь решить?

Глобально - наверное, изобрести велосипед. Локально - примерно так:


// такие шаблоны специализируются для многих T
template<class T>
Result<string> tojson(const T&);

template<class T>
Result<string>> toxml(const T&);

template<template<class A> string foo(const A&)>
class Serialization {
public:
    template<class T>
    Result<vector<uint8_t>> meth(const T& o) {
        return bzz(foo<T>(o));
    }
};

// в JSONSerialization::meth невозможно передать T,
// для которого не определена специализация tojson<T>
typedef Serialization<tojson> JSONSerialization;

// в XMLSerialization::meth невозможно передать T,
// для которого не определена специализация toxml<T>
typedef Serialization<toxml> XMLSerialization;

На самом деле всё сложнее, но суть я вроде изложил.

tailgunner ★★★★★
() автор топика
Ответ на: комментарий от intelfx

Но, Капитан, это потребует создавать шаблонные классы-обертки для уже существующих шаблонных функций, и параметризовать Serialization этими дурацкими обертками. Это выход на случай, когда красивого выхода нет.

tailgunner ★★★★★
() автор топика
Ответ на: комментарий от tailgunner

Это выход на случай, когда красивого выхода нет.

Насколько мне видно, его нет. Я тебе первым сообщением написал, что параметризация в C++ возможна только тремя видами сущностей, и то, что ты хочешь, в этот список не входит.

intelfx ★★★★★
()
Ответ на: комментарий от intelfx

Я тебе первым сообщением написал, что параметризация в C++ возможна только тремя видами сущностей

Да, спасибо, я понял.

то, что ты хочешь, в этот список не входит.

Я пока не убежден, что нормального выхода нет.

tailgunner ★★★★★
() автор топика
Ответ на: комментарий от tailgunner

это потребует создавать шаблонные классы-обертки для уже существующих шаблонных функций

А одного класса на функцию разве не хватит?

template <class T>
struct toXml {
    Result<string> operator()(const T &arg) {
        return toxml(arg);
    }
};

template <class T>
struct toJson {
    Result<string> operator()(const T &arg) {
        return tojson(arg);
    }
};

xaizek ★★★★★
()
Ответ на: комментарий от xaizek

Я имел в виду по обертке на шаблонyю функцию. Но не хочется создавать даже их - может, есть какой-то общеизвестный способ исхитриться, которого я не знаю по старости лет.

tailgunner ★★★★★
() автор топика
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Мне такой не известен. Могу ещё предложить немного сократить обёртку до:

template <class T>
struct toXml {
    static constexpr auto f = &toxml<T>;
};

xaizek ★★★★★
()

А параметризовать шаблоном функции?

Может лучше сразу функтором? Или тебе чисто из спортивного интереса надо функцию.

invy ★★★★★
()
Ответ на: комментарий от invy

Может лучше сразу функтором? Или тебе чисто из спортивного интереса надо функцию.

Шаблон функтора меня устроит, но хотелось бы, чтобы он был сделан из шаблона функции без ручного труда.

tailgunner ★★★★★
() автор топика
Ответ на: комментарий от xaizek

Спасибо, но в целевом компиляторе нет auto :)

tailgunner ★★★★★
() автор топика

А параметризовать шаблоном функции?

да вроде не шибко сложно

#include <iostream>
#include <functional>
#include <string>

template<typename T>
    struct Result {};

template<class T>
    Result<std::string> tojson(const T&) { 
        std::cout << "call tojson" << std::endl;
        return Result<std::string>{}; 
    }

template<class T>
    Result<std::string> toxml(const T&) { 
        std::cout << "call tojxml" << std::endl;
        return Result<std::string>{}; 
    }

template<typename R, typename...Arg>
class Foo 
{
public:
    Foo(const std::function<R(Arg...)>& f_) 
        : f(f_) 
        {
        }
    R invoke(Arg...args) { return f(args...); }
private:
        std::function<R(Arg...)> f;
};

int main()
{
    const auto& f1 = toxml<int>;
    Foo<Result<std::string>, int> obj1 { f1 };
    obj1.invoke(1);
    
    const auto& f2 = tojson<int>;
    Foo<Result<std::string>, int> obj2 { f2 };
    obj2.invoke(1);    
}

xperious ★★
()
Последнее исправление: xperious (всего исправлений: 1)
Ответ на: комментарий от xperious

код делает именно то, что нужно, разве нет?

Нет.

tailgunner ★★★★★
() автор топика
Ответ на: комментарий от tailgunner

Шаблон функтора меня устроит, но хотелось бы, чтобы он был сделан из шаблона функции без ручного труда.

Примитивный макрос тебе в помощь.

кроме как макросом, но это очевидное мошенничество

Это то место, где макросы используются по назначению. Не умеет цепепе со своими Тьюринг-полными шаблонами генерить такой код. Есть и другие примеры использования макр, которые рекомендованы к применению тем же isocpp.org - альтернатива std::invoke. How can I avoid syntax errors when calling a member function using a pointer-to-member-function

azelipupenko
()
Ответ на: комментарий от yoghurt

вот после такого кода, писать и иметь дело с С++ либами нет никакого желания(ты еще добавь магии и sdt c++11+)

код должен быть человеко читаем за минимальное время

твой код написанный транслируется в простейшие 3 класса с собственными методами, и кодаписания написать эти 3 класса ручками без «темплейтов» столькоже сколько у тебя строк вышло

это не «динамическое программирование» где на этапе исполнения создаются уникальные классы и твой классный алгоритм генирирует настояще ИИ по ходу
у тебя СТАТИКА СТАТИКА И ШАБЛОНЫ зачем такое делать
напиши тупо просто деревянно хоть константами чтоб читалось за секунду

тригеред шо ппц

anonymous
()
Ответ на: комментарий от azelipupenko

рекомендованы к применению тем же isocpp.org

тото гугл когда выкидывал(переименовывал(переписывал)) вебкит, в котором 90% кода было на «эталонном С++» они повыкидывали весь код типа

#define CALL_MEMBER_FN(object,ptrToMember)  ((object).*(ptrToMember))

и заодно повыкидывали 90% ссылок из кода оставив их лишь в трех файлах в нескольких функциях

так писали в 90-х, не в 2018, использовать ссылки в коде в 2018 это расстрел не меньше

anonymous
()
Ответ на: комментарий от anonymous

написать эти 3 класса ручками без «темплейтов» столькоже сколько у тебя строк вышло

у тебя СТАТИКА СТАТИКА И ШАБЛОНЫ зачем такое делать

Мде.

tailgunner ★★★★★
() автор топика
30 августа 2018 г.
Ответ на: комментарий от tailgunner

у вас с++98 ? тогда без вариантов, хотя странный компилятор с учетом того что gcc+clang покрывает все потребности на всех платформах

anonymous
()

oh, you bastard don't do that or pennywise the dancing clown will crash your head and pull your hands and legs off, hanging your helpless bodyrests on the bloody tree

#include <cstdio>

template <typename A, int (*T) (A)>
int f(int i) {
  return T(i);
}

int f_value(int i) {return i+i;}

int main() {
  printf("%d\n", f <int, &f_value> (42));
}

anonymous
()
Ответ на: комментарий от tailgunner

У меня чисто практический вопрос. Вот нагородите вы шаблонов на шаблоне а как потом это все отлаживается всмысле компилируется? Помню только километровые ошибки которые непонятно как исправлять. И ходишь по коду как по минному полю.
Сейчас ситуация с этим лучше?
Видел в инете кучу тулс для упрощения шаблонных ошибок c++.
Ну и как написать юнит тесты на шаблон?

bga_ ★★★★
()
Ответ на: комментарий от bga_

у тех кто С++ использует хотя бы не первый год, проблем с чтением ошибок не возникает

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.