如何隐藏实现帮助程序模板?
假设我在头文件中声明了两个模板函数:
template <typename T> void func1(const T& value);
template <typename T> void func2(const T& value);
并假设这些函数的实现(也在头文件中而不是在源文件中,因为它们是模板)使用一些实现辅助函数,该函数也是模板:
template <typename T> void helper(const T& value) {
// ...
}
template <typename T> void func1(const T& value) {
// ...
helper(value);
}
template <typename T> void func2(const T& value) {
// ...
helper(value);
}
在我包含头文件的任何源文件中,辅助函数都将可见。我不希望这样,因为辅助函数只是一个实现细节。有没有办法隐藏辅助功能?
Suppose that I have two template functions declared in a header file:
template <typename T> void func1(const T& value);
template <typename T> void func2(const T& value);
And suppose that the implementation of these functions (also in a header file and not in a source file, because they are templates) uses some implementation helper function, which is also a template:
template <typename T> void helper(const T& value) {
// ...
}
template <typename T> void func1(const T& value) {
// ...
helper(value);
}
template <typename T> void func2(const T& value) {
// ...
helper(value);
}
In any source file that I include the header file, the helper function will be visible. I don't want that, because the helper function is just an implementation detail. Is there a way to hide the helper function?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
一种常见的方法(例如,在许多 Boost 库中使用)是将帮助程序放在名为
details
的命名空间中,可能在单独的标头中(包含在“public”标头中)。没有办法阻止它可见和可调用,但这非常清楚地表明它是实现的一部分,而不是接口的一部分。
A common approach (as used in many Boost libraries, for example) is to put the helper in a namespace called
details
, possibly in a separate header (included from the "public" header).There's no way to prevent it from being visible, and callable, but this quite clearly indicates that it is part of the implementation, not the interface.
既定的先例是将此类事物放入专门(即一致)命名的嵌套命名空间中。 Boost 使用
命名空间详细信息
,Loki 使用私有命名空间
。显然,没有什么可以阻止任何人使用这些命名空间的内容,但这两个名称都传达了这样的含义:它们的内容不适合一般消费。话虽这么说,一个简单的替代方案是将 func1 和 func2 从自由函数模板转换为某个公共类的静态成员函数模板;这样,
helper
就可以简单地成为该类的私有成员,对外界不可见:The established precedent is to put that sort of thing in a specially (i.e. consistently) named nested namespace. Boost uses
namespace details
, Loki usesnamespace Private
. Obviously nothing can prevent anyone from using the contents of those namespaces, but both names convey the meaning that their contents aren't intended for general consumption.That being said, an easy alternative is to turn
func1
andfunc2
from free function templates into static member function templates of some common class; this way,helper
can simply be a private member of said class, invisible to the outside world:我想到了两个选项:
Two options off the top of my head:
在C++20中,您现在可以使用模块。
为此,您可以创建一个模块
some_module.cppm
保存所有函数并仅标记接口(单个函数或命名空间)使用export< /code>
,同时不公开辅助函数:
在上述情况下,仅导出函数
func1
和func2
并可在main 内访问。 cpp
:在
clang++12
您可以使用以下三个命令编译此代码:In C++20 you can now use modules.
For this you could create a module
some_module.cppm
holding all functions and marking only the interface (either the individual functions or a namespace) withexport
while not exposing the helper functions:In the case above only the functions
func1
andfunc2
are exported and can be accessed insidemain.cpp
:In
clang++12
you can compile this code with the following three commands:由于代码的用户需要查看 func1 函数的完整定义,因此无法隐藏其实现及其辅助函数实现。
但是,如果将实现移至另一个文件,用户将必须面对模板声明:
以及定义:
Since the user of your code needs to see the full definition of the
func1
function, its implementation, nor its helper function implementation, cannot be hidden.But if you move the implementation into another file, the user will only have to be confronted with the template declaration:
And the definition:
我会(如前所述)创建一个模板类,将所有函数设为静态,并将辅助函数设为私有。但除此之外,我还建议将构造函数设为私有,如下所示:
当将构造函数设为私有时,编译器将不允许此模板类的实例。所以下面的代码将变得非法:
那么为什么有人想要这个呢?因为您可能永远不希望拥有完全相同的不同实例。当编译器告诉您某个类的构造函数是私有的时,您可以假设没有必要拥有它的不同实例。
I would (as said before) make a template class, make all functions static and the helper function private. But besides that I'd also recommend making the constructor private as shown below:
When you make the constructor private, the compiler won't allow instances of this template class. So the code below would become illegal:
So why would someone want this? Because having different instances that are EXACTLY the same is something you probably never want. When the compiler tells you that the constructor of some class is private, then you can assume that having different instances of it would be unnecesarry.
我知道你的意思是你想将它隐藏得如此精细,以至于调用者只要不更改你的代码文件就无法找到你的辅助函数。我非常了解这一点,因为我最近也有非常相似的需求。
那么,将辅助函数包装在匿名命名空间中怎么样?这是我最近发现的最优雅的风格:
这种做法有效地从外部隐藏了你的内部功能。我找不到调用者可以访问匿名命名空间中的函数的任何方法。
正如 @user3635700 所回答的,将命名空间转换为充满静态函数的类通常不是一个好习惯,特别是当您有静态变量的模板时,例如:
如果此变量出现在类中,则必须初始化它课堂之外的某个地方!但是,您不能这样做,因为它是模板!卧槽!
看来,被一些人诟病的头文件中的匿名命名空间是唯一也是最完美的解决方案,可以满足我们的需求。
I know you mean that you want to hide it so finely that callers have no way to find your helper functions as long as they don't change your code file. I know it so well because I have very similar needs recently.
So how about wrapping your helper functions in an anonymous namespace? This is recently the most elegant style I found:
This practice effectively hides your internal functions from the outside. I can't find any way that a caller can access functions in anonymous namespaces.
It's usually not a good practice, as answered by @user3635700 , to convert your namespace to a class full of static functions, especially when you have templates of static variables like:
If this variable appears in a class, you'll have to initialize it somewhere outside the class! However, you can't do it because it's a template! WTF!
It seems that an anonymous namespace in the header file, which is criticized by some, is the only and the most perfect solution to our needs.