Определение статических целочисленных участников константы в определении класса

Мое понимание - то, что C++ позволяет статическим участникам константы быть определенными в классе, пока это - целый тип.

Да ведь затем, следующий код дает мне ошибку компоновщика?

#include <algorithm>
#include <iostream>

class test
{
public:
    static const int N = 10;
};

int main()
{
    std::cout << test::N << "\n";
    std::min(9, test::N);
}

Ошибка, которую я получаю:

test.cpp:(.text+0x130): undefined reference to `test::N'
collect2: ld returned 1 exit status

Интересно, если я комментирую вызов к станд.:: минута, компиляции кода и ссылки очень хорошо (даже при том, что тест:: на N также ссылаются на предыдущей строке).

Какая-либо идея относительно того, что продолжается?

Мой компилятор является gcc 4.4 на Linux.

104
задан b4hand 25 March 2015 в 15:12
поделиться

5 ответов

Насколько я понимаю, C ++ позволяет определять статические константные члены внутри класса, если это целочисленный тип.

Вы вроде правы. Вы можете инициализировать статические константные интегралы в объявлении класса, но это не определение.

http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=/com.ibm.xlcpp8a.doc/language/ref/cplr038.htm

Интересно, если бы я закомментируйте вызов std :: min, код компилируется и связывается нормально (хотя test :: N также упоминается в предыдущей строке).

Есть идеи, что происходит?

std :: min принимает свои параметры по константной ссылке. Если бы они брали их по значению, у вас не было бы этой проблемы, но, поскольку вам нужна ссылка, вам также нужно определение.

Вот глава / стих:

9.4.2/4 - Если элемент данных static имеет целочисленный тип const или const ], его объявление в определении класса может указывать инициализатор константы , который должен быть выражением интегральной константы (5.19). В этом случае член может появляться в целочисленных постоянных выражениях. Этот член все равно должен быть определен в области пространства имен, если он используется в программе, а определение области пространства имен не должно содержать инициализатор .

См. Ответ Чу, чтобы узнать о возможном обходном пути.

70
ответ дан 24 November 2019 в 04:11
поделиться

Пример Бьярна Страуструпа в его FAQ по C ++ предполагает, что вы правы, и вам нужно определение, только если вы берете адрес.

class AE {
    // ...
public:
    static const int c6 = 7;
    static const int c7 = 31;
};

const int AE::c7;   // definition

int f()
{
    const int* p1 = &AE::c6;    // error: c6 not an lvalue
    const int* p2 = &AE::c7;    // ok
    // ...
}

Он говорит «Вы можете взять адрес статического члена, если (и только если) он имеет внеклассное определение» . Это говорит о том, что это сработало бы в противном случае. Возможно, ваша функция min как-то за кулисами вызывает адреса.

47
ответ дан 24 November 2019 в 04:11
поделиться

Другой способ сделать это, в любом случае для целочисленных типов, это определить константы как перечисления в классе:

class test
{
public:
    enum { N = 10 };
};
23
ответ дан 24 November 2019 в 04:11
поделиться

C ++ позволяет определять статические константные члены внутри класса

Нет, пункт 3.1 §2 гласит:

Объявление является определением, если оно не объявляет функцию без указания тела функции (8.4), это содержит спецификатор extern (7.1.1) или спецификацию связывания (7.5) и ни инициализатор, ни тело функции, он объявляет статический член данных в определении класса (9.4), это имя класса объявление (9.1), это объявление непрозрачного перечисления (7.2) или объявление typedef (7.1.3), объявление-использование (7.3.3) или директива-использование (7.3.4).

3
ответ дан 24 November 2019 в 04:11
поделиться

Не только int. Но вы не можете определить значение в объявлении класса. Если у вас есть:

class classname
{
    public:
       static int const N;
}

в файле .h, тогда вы должны иметь:

int const classname::N = 10;

в файле .cpp.

11
ответ дан 24 November 2019 в 04:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: