链接类静态变量而不包含整个类声明

时间:2018-11-09 12:20:59

标签: c++ static

假设我有一个源文件A.cpp:

#include<string>

struct A {
  static const std::string a;
  static const std::string b;
  static const std::string c;
};

const std::string A::a{"1"};
const std::string A::b{"2"};
const std::string A::c{"3"}; 

并且要在另一个翻译单元中使用A::b。通常的方法是将A.cpp分为声明A.hpp和定义,包括第一个。

#include<iostream>
#include<A.hpp>

int main(){
  std::cout << A::b << "\n";
  return 0;
}

那当然可以,但是我想避免包含类声明,因为在我的情况下,A很大并且具有繁琐的依赖关系。

理想情况下,我想要类似

struct A; 
external const std::string A::m; 

但是会产生不完整的类型错误。

可以依靠通过其他非类全局变量进行链接。

const std::string A::b{"2"};
const std::string* bptr{&A::b};

并在另一个源文件中将其声明为

extern const std::string* bptr;

这是正确的方法,但对我来说却有点丑陋,因为需要引入多余的实体。

另一种对我有用的把戏。

struct A {
  static const std::string b;
};

int main(){
  std::cout << A::b << "\n";
  return 0;
}

它看起来不错,但很笨拙,即使是私人会员也可以使用。合法吗就是说,有什么定义这种行为的东西吗?

3 个答案:

答案 0 :(得分:1)

最后显示的技巧可能是最糟糕的黑客攻击,并且有一天会适得其反-因为它“掩盖”了另一个定义。这里没有“中间”(除了许多“ hacks”之外),要么使类定义完整显示,要么将字符串定义从类中移出。

它看起来不错,但很笨拙,即使是私人会员也可以使用。合法吗?

取决于上下文,如果第三个单元同时使用了这两个单元,您将回到原始问题上。它之所以私下工作是因为它是另一种定义,因此一开始就不是私下的。

答案 1 :(得分:0)

乍一看,最后一个变种在我看来是某种黑魔法。但是我认为它为什么起作用的越多,我认为它几乎是有效的。

一个定义规则。实际上有两个实体要看:一个字符串和一个类。

该字符串完全遵循一个定义规则。那让我感到困惑。它与在不同来源中声明相同的全局变量没有太大区别。如果存在相同定义的其他引用,则链接程序永远不会有任何问题。这种双重声明没有做任何特殊的事情,只是提供了两个引用相同的定义。而且,是的,链接器不在乎不同声明的不同访问修饰符。

该类违反了一个定义规则。在提供的示例中,差异不会破坏任何内容。但是,将非静态成员添加到定义之一,并尝试在具有不同类定义的翻译单元之间移动对象,这开始引起人们的注意。

从技术上讲,维持这两个定义并不难,但无论如何都要避免。

而且,也许我会坚持昆汀建议的通过附加功能提供访问权限的解决方案。

答案 2 :(得分:0)

如果json_normalize中仅包含静态成员变量,则可以将A从结构更改为名称空间(将A更改为struct,并摆脱掉所有变量名前面的namespace)。然后,您可以将“ A.h”拆分为多个头文件,以便仅包含所需的部分。所有变量的定义可以在一个.CPP文件中,也可以在多个文件中分割。