奇怪的 C++ link 错误
Strange C++ link error
当我尝试编译这个时,
#include <iostream>
struct K{
const static int a = 5;
};
int main(){
K k;
std::cout << std::min(k.a, 7);
}
我得到关注。 gcc
和 clang
都给出类似的错误:
/tmp/x-54e820.o: In function `main':
x.cc:(.text+0xa): undefined reference to `K::a'
clang-3.7: error: linker command failed with exit code 1 (use -v to see invocation)
如果我执行以下操作,它编译没有问题。这与std::min
的写法有关吗?
#include <iostream>
struct K{
const static int a = 5;
};
int main(){
K k;
std::cout << std::min((int) k.a, 7); // <= here is the change!!!
}
另一种避免错误的方法是我自己做 min()
:
template <class T>
T min(T const a, T const b){
return a < b ? a : b;
}
类 C 预处理器 MIN
也可以正常工作。
这个问题经常被问到。 我认为这是 clang 中的一个错误。 a
被过早检测为常量表达式,编译器未生成它的定义。(请参阅评论中的更正)
std::min
通过 const 引用获取其参数,因此必须存在定义。
#include <iostream>
struct K{
const static int a = 5;
};
int main(){
K k;
std::cout << std::min(k.a, 7);
}
这是一个可移植的解决方法替代方法:
#include <iostream>
struct K{
constexpr static int a() { return 5; }
};
int main(){
K k;
std::cout << std::min(k.a(), 7);
}
std::min
通过引用接受参数。将引用绑定到一个对象意味着该对象是 odr-used([basic.def.odr]/2 中有一个代码示例与您的示例几乎相同)。
但是在 (int)k.a
的情况下,k.a
不是 odr-used;因为它正在执行产生常量表达式的左值到右值转换。 (这里也有一些其他条件,但您的代码没问题)。
如果一个对象是 odr-used 那么它必须只有一个定义;违反此规则不需要诊断。所以第一种情况可能会或可能不会被接受;必须接受第二种情况。
在您自己的 min
版本中,它按值获取参数,这类似于 (int)k.a
情况 - 对 k.a
采取的唯一操作是右值转换以初始化你的 min
的参数。
您可以在 C++ 标准草案的 [basic.def.odr] 部分阅读有关 odr-use 的完整规则集。
您已经在您的结构中声明了一个静态变量 (a),但您还没有定义它。
struct K
{
const static int a; // declaration
};
const int K::a = 5; // definition
int main()
{
std::cout << std::min(K::a, 7);
}
您可能会发现 this link 有帮助。
我也同意 Richard Hodges 的回答。
当我尝试编译这个时,
#include <iostream>
struct K{
const static int a = 5;
};
int main(){
K k;
std::cout << std::min(k.a, 7);
}
我得到关注。 gcc
和 clang
都给出类似的错误:
/tmp/x-54e820.o: In function `main':
x.cc:(.text+0xa): undefined reference to `K::a'
clang-3.7: error: linker command failed with exit code 1 (use -v to see invocation)
如果我执行以下操作,它编译没有问题。这与std::min
的写法有关吗?
#include <iostream>
struct K{
const static int a = 5;
};
int main(){
K k;
std::cout << std::min((int) k.a, 7); // <= here is the change!!!
}
另一种避免错误的方法是我自己做 min()
:
template <class T>
T min(T const a, T const b){
return a < b ? a : b;
}
类 C 预处理器 MIN
也可以正常工作。
这个问题经常被问到。 我认为这是 clang 中的一个错误。 (请参阅评论中的更正)a
被过早检测为常量表达式,编译器未生成它的定义。
std::min
通过 const 引用获取其参数,因此必须存在定义。
#include <iostream>
struct K{
const static int a = 5;
};
int main(){
K k;
std::cout << std::min(k.a, 7);
}
这是一个可移植的解决方法替代方法:
#include <iostream>
struct K{
constexpr static int a() { return 5; }
};
int main(){
K k;
std::cout << std::min(k.a(), 7);
}
std::min
通过引用接受参数。将引用绑定到一个对象意味着该对象是 odr-used([basic.def.odr]/2 中有一个代码示例与您的示例几乎相同)。
但是在 (int)k.a
的情况下,k.a
不是 odr-used;因为它正在执行产生常量表达式的左值到右值转换。 (这里也有一些其他条件,但您的代码没问题)。
如果一个对象是 odr-used 那么它必须只有一个定义;违反此规则不需要诊断。所以第一种情况可能会或可能不会被接受;必须接受第二种情况。
在您自己的 min
版本中,它按值获取参数,这类似于 (int)k.a
情况 - 对 k.a
采取的唯一操作是右值转换以初始化你的 min
的参数。
您可以在 C++ 标准草案的 [basic.def.odr] 部分阅读有关 odr-use 的完整规则集。
您已经在您的结构中声明了一个静态变量 (a),但您还没有定义它。
struct K
{
const static int a; // declaration
};
const int K::a = 5; // definition
int main()
{
std::cout << std::min(K::a, 7);
}
您可能会发现 this link 有帮助。
我也同意 Richard Hodges 的回答。