【问题标题】:Is there a way to avoid constexpr function used in header file from entering global scope without extra namespace for it?有没有办法避免头文件中使用的 constexpr 函数在没有额外命名空间的情况下进入全局范围?
【发布时间】:2019-06-24 19:53:53
【问题描述】:

我有一个头文件,其中的代码看起来像这样:

constexpr uint32 GenTag(const char tag[5]) { ... }

class SomeClass
{
   static constexpr uint32 TAG1 = GenTag("smth");
   static constexpr uint32 TAG2 = GenTag("abcd");
};
//constexpr needed for switch-case statement

问题是函数GenTag() 属于全局范围,如果可能的话我想避免它。

我想在课堂上声明它,但用constexpr 是不可能的(这里解释:constexpr not working if the function is declared inside class scope)。

c++ 在标题末尾是否有类似“未声明”的函数(可能是一些宏技巧)?还是我错过了任何其他选择?如果没有更好的方法存在,我可能会使用额外的(可能是过多的)命名空间,但想问问是否有其他想法。

【问题讨论】:

  • 标题中真的需要GenTag 吗?静态类成员需要在 cpp 文件中的类之外进行初始化,因此您只需在 cpp 文件中定义GenTag,使其不存在于头文件中。
  • 嗨内森。 constexpr 并非如此,因为它们仅内联定义(所以是的,我需要在标题中使用它)。我在这里需要 constexpr 而不是 const 因为它在 switch-case 语句中使用。可能需要将其添加到问题中
  • 真的有什么问题吗?那些多重定义并不是问题。
  • 嗨,讲故事的人。我关心它,因为可能有其他函数接受具有相同名称 GenTag 的 const char 数组,该函数具有多个类的特定版本

标签: c++ header-files constexpr


【解决方案1】:

没有办法在 C++ 中“取消声明”函数或变量(头文件与否——头文件只是包含在当前翻译单元中)。您需要使用命名空间,或将GenTag 设为宏。您可以使用 #undef MACRONAME 取消定义宏。

【讨论】:

    【解决方案2】:

    GenTag() 定义为继承结构中的static constexpr 方法怎么样?

    如果您希望 GenTag() 仅在 SomeClass 内部可用,则可以将其设为 private 并在包含 GenTag() 的类中将 SomeClass 定义为 friend

    我的意思是……如下所示

    #include <iostream>
    
    struct SomeClass;
    
    class foo
     {
       static constexpr char GenTag(const char tag[5])
        { return tag[0]; }
    
       friend SomeClass;
     };
    
    struct SomeClass : public foo
     {
       static constexpr char TAG1 = GenTag("smth");
       static constexpr char TAG2 = GenTag("abcd");
     };
    
    int main()
     {
       std::cout << "Tag1: " << SomeClass::TAG1 << std::endl;
       std::cout << "Tag2: " << SomeClass::TAG2 << std::endl;
    
       // compilation error: 'GenTag' is a private member of 'foo'
       // static constexpr char TAG3 = foo::GenTag("wxyz");
     }
    

    使用friend 技巧,您无需从foo 继承;但是,如果没有继承,您必须将其用作foo::GetTag()

    【讨论】:

    • 一开始我认为它会起作用,因为在视觉工作室智能接受了这个技巧的情况下。但编译器没有。问题与问题中提供的链接相同,foo::GetTag() 的定义只有在 TAG1 = ... 声明定义中使用后才会被处理。绝对是一个有趣的想法,但如果我没记错的话,它是行不通的。在这两种情况下都谢谢你,这是一个很好的尝试
    • @Andrew - 很有趣。如果你从SomeClass 继承foo,你会得到同样的错误吗?
    • max66 没有对其进行测试,但几乎可以肯定,因为编译器仅在处理所有声明(即使它们是内联的)之后才处理任何类方法的定义,无论它来自哪个继承顺序。但是 constexpr 只能是内联定义的,这就是我的问题出现的原因 - 除了实现部分(即 .cpp 文件)之外,不可能在其他任何地方使用任何类内定义的 constexpr
    【解决方案3】:

    如果有人也遇到过这样的问题,我建议你不要在头文件中使用这样的 constexpr,而是考虑直接在 cpp 文件中声明-定义它。那么你肯定会避免不必要的全局范围污染。

    或者,如果有多个地方可以使用此类常量,则在没有任何类的情况下单独为它们制作一个文件,并将该文件与包含类定义标题分开包含。

    【讨论】:

      猜你喜欢
      • 2021-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-14
      • 2020-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多