如何自我记录由模板库类调用的回调函数? [英] How to self-document a callback function that is called by template library class?
问题描述
我有一个函数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
}
};
或仅将其放入与User
,或与ForLibrary
相同的名称空间中:
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
的公共接口"的一部分,因此不会造成混乱.它是User
或Library
相同名称空间中的朋友(助手)或免费函数.
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.h
或Library.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屋!