如何编写一个不断敲击输出的包装器?

Posted

技术标签:

【中文标题】如何编写一个不断敲击输出的包装器?【英文标题】:How to write a wrapper that keeps rapping the output? 【发布时间】:2016-11-01 04:00:08 【问题描述】:

基本上,我想做的是在某个抽象类上使用一个包装器,然后让相同的包装器类包装该类的任何成员函数的输出。继续这样做,以便始终包装所有对象。

喜欢(预编码)

wrap<set(1..10)> (multiply,2)
                 (divide,3)
                 (plus,5)
                 (inverse)
                 (collect first 10)
                .unwrap()

除了最后一行之外的所有行都输出了一些东西。现在似乎意义不大,但我相信我们可以在上面应用一些有趣的东西,比如:

wrap<someClass> dat;
dat.splitIntoThreads(2)
    (thingA)    .clone()
    (thingB)    (thing1)
    (thingC)    (thing2)
    (thingD)    (thing3)
    .nothing()  (thing4)
    .sync()     .exit()
    .addMerge()

这是我的换行代码:

template<class T>
struct wrap
  wrap()
  wrap(T b)a=b;
  template<class L,class...R>
  L operator() (L(T::*f)(R...),R...r)
    return a.f(r...);
  
  T a;
;

int main()
  wrap<testClass> a;
  a(&testClass::f,13,'a');

它正在工作(gcc,c++0x)。但是当我用以下内容替换第 6,7 行时(实际包装结果)

wrap<L> operator() (L(T::*f)(R...),R...r)
  return wrap<L>(a.f(r...));

编译器只是说:创建指向非类类型“int”的成员函数的指针。

我该如何解决这个问题?有没有更好的办法呢?继承是一种方式,但由于我们可能在一个包装中包含变量实例,我认为它没有用。

编辑

这是我的测试课

struct testClass
  int f(int a,char b)
    return a+b;
  
;

我使用 wrap L 而不是 wrap T 的原因是返回类型可能并不总是 T。

【问题讨论】:

你不需要 a.*f 而不是 a.f 吗? @JerryJeremiah 我记得函数指针将被视为函数,并且工作代码中的 a.f 有效 您的testclass 定义如何?你能给我们一个sn-p吗?我试图模仿你的包装。 cpp.sh/8at6z 这似乎有效。我认为错误是您对testclass 的定义。 return wrap&lt;L&gt;(a.f(r...)); 对我来说完全没问题。 问题是你想创建wrap&lt;fundamental type&gt; ex。 wrap&lt;int&gt; 因为不能有指向 int 方法的指针。 T::*f 将扩展为 int::*f 或编译器这样认为 ;)。 【参考方案1】:

你可以试试这样的:

#include <iostream>
#include <type_traits>

template<class T, bool = false>
struct wrap
  template <typename... Args>
  wrap(Args&&... args) : astd::forward<Args>(args)... ;
  template<class L, class...R>
  wrap<L,std::is_fundamental<L>::value> operator() (L(T::*f)(R...),R...r)
    return wrap<L,std::is_fundamental<L>::value > (a.*f)(r...);
  
  T a;
;

template<class T>
struct wrap <T,true>
  template <typename... Args>
  wrap(Args&&... args) : astd::forward<Args>(args)... 
  template<class L, class...R>
  wrap<L,std::is_fundamental<L>::value> operator() (L(*f)(T a, R...), R...r)
      return wrap<L,std::is_fundamental<L>::value > f(a, r...);
  
  T a;
;

class testClass 
    int m;
public:
testClass(int _m) : m_m
    int multiAdd(int x, char y) 
        m += x + y;
        return m;
    
;

int add(int a, char b)

    return a+b;


int main()
  wrap<testClass> a0;
  std::cout << a(&testClass::multiAdd,0,'d')(add,'a').a<<std::endl;

  wrap<int, true> b3;
  std::cout << b(add,'a').a<<std::endl;

cpp.sh/6icg

【讨论】:

【参考方案2】:

您的testclass 定义中似乎存在错误。请检查以下示例。

另外,operator() 中的wrap 可以作为参考返回。我认为没有必要创建用于 () 链接的临时对象。

template<class T>
struct wrap
  template <typename... Args>
  wrap(Args&&... args) : astd::forward<Args>(args)... ;

  template<class L, class...R>
  wrap<T>& operator() (L(T::*f)(R...),R...r)
    a.f(r...);
    return *this; //returning reference to current wrap object.
  
  T a;
;

一个积累数字的测试类。

class testClass 
    int m;
public:
testClass(int _m) : m_m
    int f(int x) 
        m += x;
        std::cout << ' ' << m;
        return m;
    
;

一个用法示例:

int main()
  wrap<testClass> a0;
  a(&testClass::f,13)(&testClass::f, 11)(&testClass::f,3)(&testClass::f, 21);

每一步累加的输出:

13 24 27 48

【讨论】:

您可能错误地认为结果类型与基类具有相同的类型。 @Logman 不。你能澄清一下你的意思吗?然后operato() 返回一个wrap&lt;T&gt;&amp;,这样我们就可以在返回类型上再次调用operator() testClass::f 返回 int,这意味着他想像这样包装结果 wrap 而不是 wrap。实际上他在他的问题中指出了这一点:“它正在工作(gcc,c ++ 0x)。但是当我用以下内容替换第6,7行时(实际包装结果)......”。在他的代码中,L 参数很重要,而不是 T

以上是关于如何编写一个不断敲击输出的包装器?的主要内容,如果未能解决你的问题,请参考以下文章

如何围绕 C++ 代码编写 C 包装器以公开类方法

如何在 C# 中编写我自己的包装器?

编写一个包装器将现有的 REST API 公开为 SOAP Web 服务?

如何在 C++ 中编写独立于平台的包装函数 [重复]

如何编写包装类以将 Qt 信号映射到 C# 事件(通过 C++/CLI)

如何制作 Qt 线程包装器