C++ 如何在标头中公开引用变量?

C++ 如何在标头中公开引用变量?,c++,reference,header-files,C++,Reference,Header Files,为了方便起见(MVCE),我试图在boost::bimap的一侧创建一个参考变量cParamIDsByAge: 尝试#1 代码.h #include <boost/bimap.hpp> typedef boost::bimap <int, int> ParamIDs; extern const ParamIDs cParamIDs; extern auto &cParamIDsByAge = cParamIDs.left; #include <boost

为了方便起见(MVCE),我试图在
boost::bimap
的一侧创建一个参考变量
cParamIDsByAge

尝试#1 代码.h

#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;
extern auto &cParamIDsByAge = cParamIDs.left;
#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;
auto &cParamIDsByAge = cParamIDs.left;
#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;
extern const auto &cParamIDsByAge;
#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;

extern const decltype(cParamIDs.left)& cParamIDsByAge;
// or
extern decltype((cParamIDs.left)) cParamIDsByAge;
// or
extern const ParamIDs::left_map& cParamIDsByAge;
#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;
inline auto& cParamIDsByAge() { return cParamIDs.left; }
编译器抱怨:

code.h:5:14: warning: ‘cParamIDsByAge’ initialized and declared ‘extern’
extern auto &cParamIDsByAge = cParamIDs.left;
            ^~~~~~~~~~~~~~
code.cpp:4:7: error: conflicting declaration ‘auto& cParamIDsByAge’
auto &cParamIDsByAge = cParamIDs.left;
    ^~~~~~~~~~~~~~
In file included from code.cpp:1:0:
code.h:5:14: note: previous declaration as ‘const boost::bimaps::views::map_view<boost::bimaps::relation::member_at::left, boost::bimaps::detail::bimap_core<int, int, mpl_::na, mpl_::na, mpl_::na> >& cParamIDsByAge’
extern auto &cParamIDsByAge = cParamIDs.left;
            ^~~~~~~~~~~~~~
代码.cpp

#include "code.h"

// In my code this inits the variable with some data via a function.
const ParamIDs cParamIDs {};
auto &cParamIDsByAge = cParamIDs.left;
#include "code.h"

const ParamIDs cParamIDs {};
#include "code.h"
const ParamIDs cParamIDs {};
auto &cParamIDsByAge = cParamIDs.left;
#include "code.h"

const ParamIDs cParamIDs {};
auto &cParamIDsByAge = cParamIDs.left;
但他们抱怨:

error: multiple definitions of cParamIDsByAge

尝试#3 我没有初始化标题中的引用:

代码.h

#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;
extern auto &cParamIDsByAge = cParamIDs.left;
#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;
auto &cParamIDsByAge = cParamIDs.left;
#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;
extern const auto &cParamIDsByAge;
#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;

extern const decltype(cParamIDs.left)& cParamIDsByAge;
// or
extern decltype((cParamIDs.left)) cParamIDsByAge;
// or
extern const ParamIDs::left_map& cParamIDsByAge;
#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;
inline auto& cParamIDsByAge() { return cParamIDs.left; }
编译器抱怨头文件:

error: declaration of ‘const auto& cParamIDsByAge’ has no initializer

错误消息<代码>代码。H:5:14:警告:“CPARAMIDsBeAGE”初始化并声明“ExtLeNe/<代码>非常简单:在C++中,声明为<代码> ExtNe<代码>的变量可能没有初始化器。(换句话说,

extern
只能出现在声明中,而不能出现在定义中)

示例用法可能是:

extern int &foo;

// ... cpp file

int bar;
int &foo = bar;

要在代码中实现这一点,还存在另一个问题,即需要将
int
替换为
boost::bimap::left
。您不能在
extern
声明中使用
auto
,因为没有可推断的初始值设定项

boost::bimap
碰巧将其定义为typedef,因此解决方案非常简单:

extern ParamIDs::left_map const &x;

// ... in cpp

const ParamIDs c{};
ParamIDs::left_map const &x = c.left;
如果该typedef不存在,那么您仍然可以使用
declval
decltype
来执行


注1:我认为标准不清楚是否
auto const&x=c.left
应该在这里工作,但是gcc和clang都拒绝它。

将标题中的行更改为以下内容:

// REMOVE: extern auto &cParamIDsByAge = cParamIDs.left;
extern const decltype(cParamIDs.left) &cParamIDsByAge;
这是正确地向前声明引用变量。其余部分应按原样工作。

解决方案1 在头文件中,在不使用auto的情况下声明
cParamIDsByAge
的类型,并且不初始化它:

代码.h

#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;
extern auto &cParamIDsByAge = cParamIDs.left;
#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;
auto &cParamIDsByAge = cParamIDs.left;
#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;
extern const auto &cParamIDsByAge;
#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;

extern const decltype(cParamIDs.left)& cParamIDsByAge;
// or
extern decltype((cParamIDs.left)) cParamIDsByAge;
// or
extern const ParamIDs::left_map& cParamIDsByAge;
#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;
inline auto& cParamIDsByAge() { return cParamIDs.left; }
解决方案2 使用函数而不是变量:

代码.h

#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;
extern auto &cParamIDsByAge = cParamIDs.left;
#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;
auto &cParamIDsByAge = cParamIDs.left;
#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;
extern const auto &cParamIDsByAge;
#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;

extern const decltype(cParamIDs.left)& cParamIDsByAge;
// or
extern decltype((cParamIDs.left)) cParamIDsByAge;
// or
extern const ParamIDs::left_map& cParamIDsByAge;
#include <boost/bimap.hpp>

typedef boost::bimap <int, int> ParamIDs;
extern const ParamIDs cParamIDs;
inline auto& cParamIDsByAge() { return cParamIDs.left; }
#包括
typedef boost::bimap参数;
外部常量参数cParamIDs;
内联自动&cParamIDsByAge(){return cParamIDs.left;}

变量不能初始化两次。(因此不能在标题中使用
auto
)@M.M OK,但必须初始化引用变量。我能想到的最好的方法是我在第二次尝试中所做的,但这不起作用。需要常量限定符如果它包括
常量
,那么它也将包括
&
。您可以通过添加两个额外的括号使其同时包含
const
&
decltype((cParamIDs.left))
联机检查:可以编译了,谢谢!我知道现在的问题是什么。PS:我读到引用是隐式的
const
,所以不需要
const
关键字。引用不是隐式的const,你可能读到有人混淆了引用和指针之间的区别。不是引用是const,而是它引用的对象。一旦初始化,就不能修改引用本身,因此从这个意义上说,它是隐式常量。要显式声明引用常量,您必须编写类似
intbar;int&const foo=bar,但此代码格式不正确,并且没有关联的行为。另请参见其他地方。@il--ya
const
是一个关键字,只有当它们符合条件时才是
const
。它并不意味着任何不可修改的东西。此外,还可以修改非常量引用(这意味着修改引用所引用的对象)。我想你的意思是,引用一旦被初始化,就不能反弹到不同的对象,但这与
const
或常量无关。在引擎盖下,引用被有效地视为一个取消引用的常量指针,而“边界”则有效地为该指针指定了一个初始值。实际上,可以使用一些特定于实现的代码对其进行修改(从而恢复)。“此外,非常量引用可以修改(这意味着修改引用所引用的对象)。”-但这是两件不同的事情,修改引用和修改引用的对象,你不这么认为吗?