0

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

template<typename T, typename LogFunc>
class
{

(其中 LogFunc 应默认为“nop”函数)

想法是有一个类为类型 T 的实例定义一些功能,例如检查数字是否为偶数,并且还可以通过调用来记录

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

或许

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

可以做到吗?通过阅读 SO 上的 A,lambdas 作为 templ 参数有点问题。顺便说一句,如果有人关心是我尝试过的,但它会打印出来

:(

4

3 回答 3

3

问题是 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);
}
于 2012-10-30T18:29:49.963 回答
2

这不会直接回答,但会提供一些有关您所做工作的提示。

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

  • LogFunc(t)创建一个临时LogFunct定作为参数(您实际上是在调用LogFunc::LogFunc(T&)构造函数)。
  • LogFunc lf; lf(t);创建一个Logfunc名为 lf 的堆栈生存默认构造,并lf(t)调用其LogFunc::operator()(T&)成员函数。
  • LogFunc()(t)创建一个临时的默认构造的 LogFunc 并在其上调用 operator()(T&)。

关于 lambda,它们实际上是类,其构造函数采用捕获的变量,其 operator() 采用您声明的参数。但是它们只存在于编译器的“内部”,并且没有您可以引用的“名称”。

你可以做的是用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
于 2012-10-30T18:07:32.110 回答
1

其他答案都很好,但你也可以只传入一个带有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);
}
于 2012-10-30T19:33:35.727 回答