20

我有一个仅供本地使用的类(即,它的对应只是它定义的 c++ 文件)

class A {
public:
    static const int MY_CONST = 5;
};

void fun( int b ) {
    int j = A::MY_CONST;  // no problem
    int k = std::min<int>( A::MY_CONST, b ); // link error: 
                                            // undefined reference to `A::MY_CONST` 
}

所有代码都驻留在同一个 c++文件中。在windows上使用VS编译时,完全没有问题。
但是,在 Linux 上编译时,我undefined reference只收到第二条语句的错误。

有什么建议么?

4

6 回答 6

26

std::min<int>的论点都是const int&(不仅仅是) ,int. int而且您不能传递引用,A::MY_CONST因为它没有定义(仅声明)。

.cpp在类之外的文件中提供定义:

class A {
public:
    static const int MY_CONST = 5; // declaration
};

const int A::MY_CONST; // definition (no value needed)
于 2013-06-06T08:46:55.640 回答
6
// initialize static constants outside the class

class A {
public:
    static const int MY_CONST;
};

const int A::MY_CONST = 5;

void fun( int b ) {
    int j = A::MY_CONST;  // no problem
    int k = std::min<int>( A::MY_CONST, b ); // link error: 
                                            // undefined reference to `A::MY_CONST` 
}
于 2013-06-06T08:49:40.513 回答
4

要解释这里发生的事情:

你在类中声明static const了整数,这个“特性”是为了能够将它用作常量表达式,即用于本地数组大小、模板非类型参数等。如果编译器想要使用这个常量表达式,它必须能够查看它在该翻译单元中的价值。

9.5/3

如果非易失性 const 静态数据成员是整数或枚举类型,则其在类定义中的声明可以指定一个大括号或等式初始化器,其中作为赋值表达式的每个初始化器子句都是一个常量表达式 (5.19) . 文字类型的静态数据成员可以在类定义中用 constexpr 说明符声明;如果是这样,它的声明应指定一个大括号或等式初始化器,其中作为赋值表达式的每个初始化器子句都是一个常量表达式。[注意:在这两种情况下,成员都可能出现在常量表达式中。— 尾注]如果该成员在程序中被 odr-used (3.2) 和命名空间范围定义,则该成员仍应在命名空间范围内定义不应包含初始化程序

odr-used 意味着形成对该变量的引用或获取它的地址。

std::min通过引用获取它的参数,因此它们是odr-used

解决方案:

定义它!

class A
{
    static const int a = 5;
};

const int A::a; //definition, shall not contain initializer
于 2016-06-23T08:10:05.087 回答
2

您还可以将 const 值保存到局部变量中。

class A {
public:
    static const int MY_CONST = 5;
};

void fun( int b ) {
    int j = A::MY_CONST;  // no problem
    int k = std::min<int>( A::MY_CONST, b ); // link error: undefined reference to `A::MY_CONST` 
    int l = std::min<int>( j, b);  // works
}
于 2019-05-20T12:03:03.800 回答
0

我的情况很奇怪

template<class T> class Strange {

public:
  static const char gapchar='-';
  };

template<class T> void Strange<T> method1 {
      char tmp = gapchar;
}

template<class T> void Strange<T> method2 {
    char tmp = gapchar;
}

我包括上面的类,它已经工作了好几年了。

我添加了另一种方法,基本上相同的签名,只是读取 gapchar。

我只为第三种方法得到未定义的错误,即使我正在使用所有三种方法。

然后我改变了初始化静态变量的方式

未在类定义中初始化:

static const char gapchar;

template<class T> const char Strange<T>::gapchar='-';

这解决了问题。我无法弄清楚为什么在类定义部分中初始化 int 或 char 类型(仅允许的两种类型)的旧方法仅对其中一种方法起作用,而对其他方法不起作用。

于 2014-10-02T15:59:43.257 回答
0

如果您正在使用一些仅限标题的东西并且希望避免添加.cpp文件,那么您似乎可以这样做:

class A {
public:
    static inline const int MY_CONST = 5;
};

(or `static inline constexpr`)

This requires C++17
于 2022-02-17T10:07:28.073 回答