Как использовать std :: function или lambda в качестве (необязательного) параметра шаблона?

Привет, я играл с TMP и думал о создании класса
это выглядит примерно так:

template<typename T, typename LogFunc>
class
{

(где LogFunc должен быть установлен по умолчанию в функцию «nop»)

Идея состоит в том, чтобы иметь класс, который определяет некоторые функциональные возможности для экземпляров типа T, например, проверяет, является ли число четным, а также имеет возможность войти, вызвав

void memberFunc(T& t)
{
LogFunc(t);
}

или, может быть

void memberFunc(T& t)
{
LogFunc lf;
lf(t);
}

Это можно сделать?
Из чтения A на SO лямбды вроде проблемных параметров.
Кстати, если кто-то заботится этот это то, что я пытался, но это распечатывает

🙁

0

Решение

Проблема в том, что лямбда-тип является синглтоном, поддерживаемым компилятором; у него есть только одно значение — сама лямбда; кроме того, тип имеет удаленный конструктор. Таким образом, вы не можете передавать лямбды как часть создания шаблона, даже с decltype. Но ничто не мешает вам передавать их в качестве аргументов конструктора.

Однако здесь мы сталкиваемся с другой проблемой: аргументы конструктора не используются для вывода экземпляра шаблона (именно поэтому стандартная библиотека предоставляет такие утилиты, как make_pair и make_tuple). Итак, нам нужна шаблонная фабричная функция.

При этом решение довольно простое:

template<typename T, typename LogFunc>
class Foo {
public:
Foo(const T& t, LogFunc fn) : t_(t), lfn_(fn) {}
//...

private:
T t_;
LogFunc lfn_;
};

struct Noop {
template<typename...A>
void operator()(A...) { };
};

template<typename T, typename LogFunc=Noop>
Foo<T, LogFunc> make_foo(const T& t, LogFunc func=LogFunc()) {
return Foo<T, LogFunc>(t, func);
}
3

Другие решения

Это не будет отвечать напрямую, но дает несколько подсказок о том, что вы сделали.

LogFunc Параметр является типом (не объектом), следовательно,

  • LogFunc(t) создает временный LogFunc дающий t в качестве параметра (вы на самом деле вызываете LogFunc::LogFunc(T&) застройщик).
  • LogFunc lf; lf(t); создает стек по умолчанию Logfunc, названный LF, и lf(t) называет его LogFunc::operator()(T&) функция-член.
  • LogFunc()(t) создает временный LogFUnc, созданный по умолчанию, и вызывает operator () (T&) в теме.

Что касается лямбд, это фактически классы, конструктор которых принимает захваченные переменные, а оператор () принимает параметры, которые вы объявляете. Но они существуют только «внутренне» для компилятора и не имеют «имени», на которое вы можете ссылаться.

Что вы можете сделать, это вывести его тип с decltypeили со свободной функцией.

Обычно параметрический функциональный класс хранит объект функции, инициализированный при построении.

#include <iostream>

template<class Fn>
class LogFunc
{
public:
LogFunc(Fn f) :fn(f) {}

template<class T>
void memberFunc(T& t)
{ fn(t); }
private:
Fn fn;
};

template<class Fn>
LogFunc<Fn> makeLogFunc(Fn f)
{ return LogFunc<Fn>(f); }

int main()
{
int x=5;

auto lf = makeLogFunc([](int& a){ std::cout << a << std::endl; });
lf.memberFunc(x);

return 0;
}

скомпилировать как «g ++ -pedantic -Wall -std = c ++ 11» и выйдет

5
2

Другие ответы все в порядке, но вы также можете просто передать аргумент конструктора с std::function<T>, Это выглядит так:

#include <functional>
#include <iostream>

template <typename T> void someOther(T val){
std::cout << "used other "<<val<<std::endl;
}

template <typename T> void noop(T val){
std::cout << "noop "<<val<<std::endl;
}

template<typename T>
struct A{
A(std::function<void(T)> f =noop<T> ) : mf(f){}
void memberFunc(T valx){
mf(valx);
}
std::function<void(T)> mf;
};

int main(){
A<int> aNoop; ;
A<float> aSomeOther{someOther<float>} ;
aNoop.memberFunc(5);
aSomeOther.memberFunc(3.55);
}

Альтернатива — использовать классы функторов, например:

#include <iostream>
template <typename T> struct OtherC{
void operator()(T v){ std::cout <<"other "<<v<<std::endl; };
};
template <typename T> struct NoopC{
void operator()(T){ std::cout << "noop"<<std::endl; };
};
template<typename T, template <typename X> class F = NoopC >
struct A{
static void memberFunc(T valx){ F<T>()(valx); }
};
int main(){
A<int> aNoop;
A<float,OtherC> aSomeOther ;
aNoop.memberFunc(5);
aSomeOther.memberFunc(3.55);
}
1
По вопросам рекламы [email protected]