在 C++ 头文件库中定义“隐藏”常量

Jac*_*mme 1 c++ constants clang header-files c++17

我正在创建一个仅包含 C++ 标头的库实现,其中定义了多个我static constexpr只想在库中使用的常量(定义为 s),以使我的代码更加清晰易读。我认为拥有内部链接足以从我包含此库的任何其他源文件中“隐藏”这些常量。

但是,在将此标头包含在我正在为其编写单元测试的另一个文件中之后,我收到了类似的错误redefinition of '<constant_name>'(测试源文件有自己的同名常量,因为它们在某些测试用例中很有用,也定义为static constexprs)。经过进一步阅读后,我现在了解到内部链接意味着常量在翻译单元之外不可用,但翻译单元包括源文件及其包含的任何标头。这可以解释为什么我会收到该redefinition错误,因为测试源文件和库头文件中都存在具有相同名称的常量,并且它们最终成为单个翻译单元。

目前,我已将上述常量包装在命名空间中以避免冲突。然而,这并不理想。例如,当我使用命名空间作为前缀时,我仍然会在其他文件中获得这些常量的自动完成建议。相反,我希望它们完全隐藏。

我的问题是是否有办法解决这个问题。有没有某种方法可以使这些常量仅在标头本身内真正可见,并且对包含它的任何文件不可见?

编辑:这里有一些代码来演示我的意思。

library.hpp

static constexpr int USEFUL_CONSTANT = 5;

namespace library {
    ...library implementation here...
}
Run Code Online (Sandbox Code Playgroud)

tests.cpp

#include "library.hpp"

// Constant happens to be useful in tests too, but I don't 
// want to expose it for everybody, so I redefine it here
static constexpr int USEFUL_CONSTANT = 5;

...tests here...
Run Code Online (Sandbox Code Playgroud)

我收到重新定义错误,因为这两个常量都是同一翻译单元的一部分。

use*_*670 5

一些可行的方法:

  1. 内部命名空间,(增强风格)
namespace mylib
{
    namespace detail
    {
        inline constexpr int const goodenough{42};
    }
    
    int foo(void)
    {
        return detail::goodenough;
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 转换为某个类的字段,并通过声明private static授予访问权限friend
namespace mylib
{
    int foo(void);

    class detail
    {
        friend int ::mylib::foo(void);
 
        static inline constexpr int const goodenough{42};
    };
    
    int foo(void)
    {
        return detail::goodenough;
    }
}
Run Code Online (Sandbox Code Playgroud)

注:constexpr暗示着inlineconst