Привет, я играл с 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 лямбды вроде проблемных параметров.
Кстати, если кто-то заботится этот это то, что я пытался, но это распечатывает
🙁
Проблема в том, что лямбда-тип является синглтоном, поддерживаемым компилятором; у него есть только одно значение — сама лямбда; кроме того, тип имеет удаленный конструктор. Таким образом, вы не можете передавать лямбды как часть создания шаблона, даже с 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);
}
Это не будет отвечать напрямую, но дает несколько подсказок о том, что вы сделали.
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
Другие ответы все в порядке, но вы также можете просто передать аргумент конструктора с 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);
}