这是一个非常基本的问题,但我不明白为什么下面的代码不能在GCC 4.6.1上编译。它在VS 2008 SP1上编译:
#include <iostream>
class MyClass
{
public:
const static int MinValue = -1000;
const static int MaxValue = 1000;
};
void printValue(int i)
{
std::cout << i << std::endl;
}
int main(int argc, char** argv)
{
printValue(MyClass::MinValue);
printValue(MyClass::MaxValue);
printValue(argc < 42 ? MyClass::MinValue : MyClass::MaxValue); //This line gives the error
}
海湾合作委员会说:
david@David-Laptop:~/temp$ g++ test.cpp
/tmp/ccN2b95G.o: In function `main':
test.cpp:(.text+0x54): undefined reference to `MyClass::MinValue'
test.cpp:(.text+0x5c): undefined reference to `MyClass::MaxValue'
collect2: ld returned 1 exit status
但是,如果我取出第三次调用'printValue',那么它会构建并正常运行。所以它与'?'有关operator ...这样使用它是无效的吗?另外,如果我更换'argc&lt; 42'与'true'或'false'它也很好。
有什么想法吗?!
答案 0 :(得分:18)
根据“一个定义规则”,如果是 odr-used ,变量必须只有一个定义。这由C ++ 11标准定义:
3.2 / 2一个变量或非重载函数,其名称显示为一个可能被评估的表达式,除非它是满足出现在常量表达式中的要求且左值到右值的转换是立即申请。
和ODR本身:
3.2 / 3每个程序应该只包含该程序中使用的每个非内联函数或变量的一个定义;无需诊断。
作为函数调用参数,它们不是 odr-used :它们是在其声明中指定值的常量,因此可以出现在常量表达式中;它们按值传递,因此立即转换为右值。
在条件表达式中使用它们时不是这种情况。由于两个都是引用相同类型的左值,根据定义条件运算符的相当复杂的规则之一,条件表达式的结果将是左值:
5.16 / 4如果第二个和第三个操作数是相同值类别且具有相同类型的glvalues,则结果属于该类型和值类别。
(此规则允许使用(a?b:c)=d
等表达式。)
因此,常量本身不会立即转换为rvalues,并且由于运行时条件,条件表达式不能出现在常量表达式中;因此,它们使用得很多,因此需要一个定义。
如您所知,将条件更改为常量表达式可修复链接错误;所以会改变一个常量的类型。但是现在的表达要求他们在一个(且只有一个)翻译单元中有一个定义:
const int MyClass::MinValue;
const int MyClass::MaxValue;
答案 1 :(得分:7)
您需要在类声明之外定义静态成员:
class MyClass
{
public:
const static int MinValue;
const static int MaxValue;
};
//implementation file
const int MyClass::MinValue = -1000;
const int MyClass::MaxValue = 1000;
答案 2 :(得分:0)
我要说明这可能是你正在使用的版本的编译器错误。正如AzzA在他的评论中指出的那样,gcc-4.5.1似乎和gcc-4.3.4一样好。我也只是用CLang 2.9测试了它,并且也接受了代码。
作为替代方案,您可以使用枚举而不是静态const来定义最小/最大值。这将节省一些输入:
#include <iostream>
class MyClass
{
public:
enum { MinValue = -1000, MaxValue = 1000 };
};
void printValue(const int i)
{
std::cout << i << std::endl;
}
int main(int argc, char** argv)
{
printValue(MyClass::MinValue);
printValue(MyClass::MaxValue);
printValue(argc < 42 ? MyClass::MinValue : MyClass::MaxValue);
}