Aar*_*aid 8 c++ extern one-definition-rule c++11 c++14
如果我按值传递一个空变量,即使它没有定义,它是否安全且合规?
我在处理代码,重载时遇到了这个问题|,以便打印向量的内容v:
v | print; // prints the vector v
Run Code Online (Sandbox Code Playgroud)
我在这里的代码对我的作品有g++和clang,即使print是extern没有关联的变量,但我不知道如果我推的标准太远.这是针对c ++ 11/c ++ 14,我想这是用c ++ 17解决的inline变量?
首先,我的初始代码.目标是允许v|print打印矢量等内容.我也有更大的目标,与范围相关,但我会在这里关注这个小例子
struct print_tag_t {};
print_tag_t print;
void operator| (std::vector<int> & x, decltype(print) ) {
for(auto elem : x) {
std::cout << elem << '\n';
}
}
int main() {
std::vector<int> v{2,3,5,7};
v | print;
}
Run Code Online (Sandbox Code Playgroud)
如果我将其移动到标题中,我可以将operator|重载设置为inline.但那怎么样print?我发现我extern可以避免关于重复符号的链接器错误
// print.hh
struct print_tag_t {};
extern // extern, as I can't use inline on a variable
print_tag_t print;
inline
void operator| (std::vector<int> & x, decltype(print) ) {
for(auto elem : x) {
std::cout << elem << '\n';
}
}
Run Code Online (Sandbox Code Playgroud)
这适合我.不知何故,即使print没有定义,我也能做到v|print.我想这是因为它是空的,因此检查没有价值,因此它永远不需要地址.
编译器是否需要允许我的v|print示例工作?在哪里澄清,print是否extern已经给出了任何定义?
编译器是否需要允许我的
v|print示例工作?在哪里澄清,印刷是否extern已经给出了任何定义?
不.你是使用odr print(你正在调用一个不产生常量表达式的左值到右值的转换),这意味着你需要一个定义print.但是,这是错误的错误类别之一,无需诊断.由于所讨论的代码不占用print任何地址,因此编译器可能会发出不需要这样定义的代码,因此链接器也会对此感到高兴.通常,它将Just Work™.
更好的解决方案是简单地更改声明print constexpr:
constexpr print_tag_t print{};
Run Code Online (Sandbox Code Playgroud)
现在,v | print不会使用odr print(因为左值到右值的转换现在将是一个常量表达式),所以甚至不需要定义,因此程序格式正确.