C++ 如何将std::function或lambda作为(可选)模板参数?

C++ 如何将std::function或lambda作为(可选)模板参数?,c++,c++11,template-meta-programming,C++,C++11,Template Meta Programming,嗨,我在和TMP玩,正在考虑生成一个类 这看起来像: template<typename T, typename LogFunc> class { 或许 void memberFunc(T& t) { LogFunc lf; lf(t); } 能做到吗? 从上面的阅读来看,lambda与temp参数一样有点问题。 顺便说一句,如果有人在乎我试过的,但它打印出来了 :( 这不会直接回答,但会给出一些关于您所做工作的提示 LogFunc参数是一种类型(不是对象),因此

嗨,我在和TMP玩,正在考虑生成一个类 这看起来像:

template<typename T, typename LogFunc>
class
{
或许

void memberFunc(T& t)
{
  LogFunc lf;
  lf(t);
}
能做到吗? 从上面的阅读来看,lambda与temp参数一样有点问题。 顺便说一句,如果有人在乎我试过的,但它打印出来了

:(


这不会直接回答,但会给出一些关于您所做工作的提示

LogFunc
参数是一种类型(不是对象),因此

  • LogFunc(t)
    创建一个临时的
    LogFunc
    t
    作为参数(实际上您正在调用
    LogFunc::LogFunc(t&)
    构造函数)
  • LogFunc-lf;lf(t);
    创建一个名为lf的、由
    LogFunc
    构造的堆栈,并且
    lf(t)
    调用其
    LogFunc::operator()(t&)
    成员函数
  • LogFunc()(t)
    创建一个临时默认构造的LogFunc,并对其调用操作符()(t&)
关于lambdas,它们实际上是类,其构造函数采用捕获的变量,其运算符()采用您声明的参数。但是它们只存在于编译器的“内部”,并且没有您可以引用的“名称”

您可以使用
decltype
或自由函数推断其类型

通常,参数化函数类存储在构造时初始化的frunction对象

#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;
}

这不会直接回答,但会给出一些关于您所做工作的提示

LogFunc
参数是一种类型(不是对象),因此

  • LogFunc(t)
    创建一个临时的
    LogFunc
    t
    作为参数(实际上您正在调用
    LogFunc::LogFunc(t&)
    构造函数)
  • LogFunc-lf;lf(t);
    创建一个名为lf的、由
    LogFunc
    构造的堆栈,并且
    lf(t)
    调用其
    LogFunc::operator()(t&)
    成员函数
  • LogFunc()(t)
    创建一个临时默认构造的LogFunc,并对其调用操作符()(t&)
关于lambdas,它们实际上是类,其构造函数采用捕获的变量,其运算符()采用您声明的参数。但是它们只存在于编译器的“内部”,并且没有您可以引用的“名称”

您可以使用
decltype
或自由函数推断其类型

通常,参数化函数类存储在构造时初始化的frunction对象

#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;
}

问题是lambda的类型是编译器强制的单例;它只有一个值,即lambda本身;此外,该类型有一个已删除的构造函数。因此,即使使用decltype,也不能将lambda作为模板实例化的一部分传递。但没有什么可以阻止您将其作为构造函数参数传递

但是,这里我们遇到了另一个问题:构造函数参数不用于推断模板实例化(这就是为什么标准库提供了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);
}
模板
福班{
公众:
Foo(const T&T,LogFunc fn):T(T),lfn(fn){
//...
私人:
T!;
LogFunc-lfn;
};
结构Noop{
模板
void运算符()(A…){};
};
模板
Foo make_Foo(const T&T,LogFunc func=LogFunc()){
返回Foo(t,func);
}

问题在于lambda的类型是编译器强制的单例;它只有一个值,即lambda本身;此外,该类型有一个已删除的构造函数。因此,即使使用decltype,也不能将lambda作为模板实例化的一部分传递。但没有什么可以阻止您将其作为构造函数参数传递

但是,这里我们遇到了另一个问题:构造函数参数不用于推断模板实例化(这就是为什么标准库提供了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);
}
模板
福班{
公众:
Foo(const T&T,LogFunc fn):T(T),lfn(fn){
//...
私人:
T!;
LogFunc-lfn;
};
结构Noop{
模板
void运算符()(A…){};
};
模板
Foo make_Foo(const T&T,LogFunc func=LogFunc()){
返回Foo(t,func);
}

其他答案都很好,但您也可以使用
std::function
传入一个构造函数参数

#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);
}
#包括
#包括
其他模板无效(T val){

std::cout其他答案都很好,但是您也可以使用
std::function
传入一个构造函数参数

#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);
}
#包括
#包括
其他模板无效(T val){

std::cout lambda不是类型,它们不能作为模板参数传递。你真的不能仅仅创建一个no-op结构来用作默认参数吗?它必须是一个运行时多态函子或lambda?
struct noop{void operator()(const t&){};
对你来说太多了吗?仅仅因为lambda的存在并不意味着你应该忘记其他的一切。这里有decltype:)尽管idk在这种情况下如何使用它(请参阅链接)@nicolabolas这不仅仅是默认的noop点,而是在我需要时实际指定参数。呃,除非我有误解,否则在粘贴的代码中,你从来没有将
log_func
设置为值。你定义了
lambdada
,但你只使用它的类型,而不是实际值。你为什么期望code显示除
以外的任何内容:(
?lambda不是类型,它们不能作为模板参数传递。你真的不能只创建一个no-op结构用作默认参数?它必须是一个运行时多态函子或lambda?
结构noop{void操作符()(const t&){};