如何自我记录由模板库类调用的回调函数? [英] How to self-document a callback function that is called by template library class?

查看:131
本文介绍了如何自我记录由模板库类调用的回调函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个函数User::func()(回调),可以由模板类(Library<T>)调用.

I have a function User::func()(callback) that would be called by a template class (Library<T>).

在开发的第一个迭代中,每个人都知道func()仅用于该单一目的.
几个月后,大多数成员忘记了func()的用途.
经过大量的重构后,某些编码器有时会删除func().

In the first iteration of development, everyone know that func() serves only for that single purpose.
A few months later, most members forget what func() is for.
After some heavy refactoring, the func() is sometimes deleted by some coders.

起初,我根本不认为这是个问题.
但是,我多次遇到此模式后,我认为我需要采取一些对策.

At first, I didn't think this is a problem at all.
However, after I re-encountered this pattern several times, I think I need some counter-measure.

如何优雅地记录下来? (可爱且简洁,没有额外的CPU开销)

How to document it elegantly? (cute && concise && no additional CPU cost)

这是一个简化的代码:-
(现实世界中的问题是散布在10多个库文件和20多个用户文件以及40多个函数中.)

Here is a simplified code:-
(The real world problem is scattering around 10+ library-files & 20+ user files & 40+ functions.)

Library.h

template<class T> class Library{
    public: T* node=nullptr;
    public: void utility(){
        node->func();  //#1
    }
};

User.h

class User{
    public: void func(){/** some code*/} //#1
    //... a lot of other functions  ...
    // some of them are also callback of other libraries
};

main.cpp

int main(){
    Library<User> li; .... ;  li.utility();
}

我可怜的解决方案

1.评论/文档

作为第一个解决方法,我倾向于添加这样的评论:-

My poor solutions

1. Comment / doc

As the first workaround, I tend to add a comment like this:-

class User{ 
    /** This function is for "Library" callback */
    public: void func(){/** some code*/}
};

但是它很快就会变脏-我必须将其添加到每个类的每个函数"中.

But it gets dirty pretty fast - I have to add it to every "func" in every class.

在实际情况下,我倾向于在函数名称前添加这样的前缀:-

In real case, I tend to prefix function name like this:-

class User{ 
    public: void LIBRARY_func(){/** some code*/}
};

这非常引人注目,但是函数名称现在已经很长了.
(尤其是当Library -class具有更长的类名时)

It is very noticeable, but the function name is now very longer.
(especially when Library-class has longer class name)

我正在考虑创建一个抽象类作为回调的接口.

I am considering to create an abstract class as interface for the callback.

class LibraryCallback{ 
    public: virtual void func()=0;
};
class User : public LibraryCallback{ 
    public: virtual void func(){/** some code*/}
};

它提供的感觉是func() something-quite-external 的. :)
但是,我必须牺牲虚拟呼叫成本(v表).
在性能至关重要的情况下,我负担不起.

It provides feeling that func() is for something-quite-external. :)
However, I have to sacrifice virtual-calling cost (v-table).
In performance-critical cases, I can't afford it.

(来自Daniel Jour的想法,谢谢!)

大约1个月后,这是我的使用方法:-

Almost 1 month later, here is how I use :-

Library.h

template<class T> class Library{
    public: T* node=nullptr;
    public: void utility(){
        T::func(node);  //#1
    }
};

User.h

class User{
    public: static void func(Callback*){/** some code*/} 
};

main.cpp

int main(){
    Library<User> li;
}

它可能更干净,但仍然缺乏自我证明.

It is probably cleaner, but still lack self-document.

推荐答案

func不是User的功能.这是User-Library<T>耦合的特征.

func is not a feature of User. It is a feature of the User-Library<T> coupling.

如果在Library<T>之外没有明确的语义,将其放在User中是一个坏主意.如果它确实具有清晰的语义,则应说明其作用,而删除它显然是一个坏主意.

Placing it in User if it doesn't have clear semantics outside of Library<T> use is a bad idea. If it does have clear semantics, it should say what it does, and deleting it should be an obviously bad idea.

将其放置在Library<T>中是行不通的,因为它的行为是Library<T>中的T的函数.

Placing it in Library<T> cannot work, because its behavior is a function of the T in Library<T>.

答案是将其放置在任何位置.

The answer is to place it in neither spot.

template<class T> struct tag_t{ using type=T; constexpr tag_t(){} };
template<class T> constexpr tag_t<T> tag{};

现在在Library.h中:

struct ForLibrary;
template<class T> class Library{
  public: T* node=nullptr;
  public: void utility(){
    func( tag<ForLibrary>, node ); // #1
  }
};

User.h中:

struct ForLibrary;
class User{ 
/** This function is for "Library" callback */
public:
  friend void func( tag_t<ForLibrary>, User* self ) {
    // code
  }
};

或仅将其放入与UserForLibrary相同的名称空间中:

or just put this into the same namespace as User, or the same namespace as ForLibrary:

friend func( tag_t<ForLibrary>, User* self );

在删除func之前,您将跟踪ForLibrary.

Before deleting func, you'll track down ForLibrary.

它不再是User的公共接口"的一部分,因此不会造成混乱.它是UserLibrary相同名称空间中的朋友(助手)或免费函数.

It is no longer part of the "public interface" of User, so doesn't clutter it up. It is either a friend (a helper), or a free function in the same namespace of either User or Library.

您可以在需要Library<User>的地方实现它,而不是在User.hLibrary.h中实现,尤其是当它仅使用User的公共接口时.

You can implement it where you need a Library<User> instead of in User.h or Library.h, especially if it just uses public interfaces of User.

这里使用的技术是标签分配",依赖于参数的查找",朋友功能",并且比起方法更喜欢自由功能.

The techniques used here are "tag dispatching", "argument dependent lookup", "friend functions" and preferring free functions over methods.

这篇关于如何自我记录由模板库类调用的回调函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆