с++: функция в качестве параметра шаблона класса

подскажите можно ли сделать следующие вещи:

  1. указать в качестве шаблона функцию, но только заданного вида:

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

    template <typename Func> // где Func - функция вида int (const int, const float)
    class CMyClass {
    };
  1. задать класс указать функцию как лямбда-функцию, например так

     using CMyClassX = classCMyClass<[](const int index, const float value) {
         return value * index;
     }>;
    

Ответы (2 шт):

Автор решения: maestro

Можно определить тип функции и подставить его в шаблон вместо typename. Лямбда-выражения в шаблон подставлять никак нельзя.

typedef int (FuncType)(const int, const float); //Объявляем тип, которому соответствует функция

template<FuncType t>
class MyClass{};


int f1(const int a, const float b)
{
    return 0;
}

int f2(float b)
{
    return 0;
}

int main()
{
    MyClass<f1> a;  //ОК
    MyClass<f2> b;  //Ошибка
    MyClass<[](const int a, const float b){}> c; //Ошибка
    return 0;
}
→ Ссылка
Автор решения: HolyBlackCat
  1. typename - это вообще не функция. Это может быть класс с перегруженным operator().

    Можно взять указатель на функцию: template <int func(const int, const float)>.

    Это эквивалентно template <int (*func)(const int, const float)>
    или template <int (*func)(int, float)>.

  2. До C++20 лямбды в принципе не могли появляться в аргументах шаблона, и Clang до сих пор не научился. Предположим что ваш компилятор так умеет.

    Если возьмете указатель на функцию, как написал выше, то лямбда не сработает, но уже по другой причине. GCC мне выдал not a valid template argument for type '...' because '...' has no linkage. Т.е. у функций, в которые преобразуются лямбды, нет linkage (грубо говоря, их нельзя объявить отдельно от определения).

    Есть другой вариант - template <auto Func>, тогда лямбды будут работать. А ограничить возвращаемый тип и параметры вот так:

    template <auto Func> requires std::same_as<decltype(+Func), int(*)(int, float)>
    

    Учтите, что такая проверка не допускает неявные преобразования (в параметрах и в возвращаемом типе). Если вы хотите их разрешить, то вместо этого проверяйте std::is_invocable_r_v.

    Третий вариант - template <typename Func>. Примерно такой же как предыдущий, только Func перед вызовом придется конструировать, а при использовании шаблона оборачивать лямбду в decltype.

→ Ссылка