Russian Qt Forum
Ноябрь 25, 2024, 07:42 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Ошибка компоновщика при использовании qMin(), qMax(), qBound()  (Прочитано 6756 раз)
zavulon
Гость
« : Сентябрь 23, 2008, 15:30 »

Попытка использовать статические константы-члены в функциях qMin(), qMax(), qBound() выдает следющую ошибку компоновщика:
   undefined reference to `<статическая константа>'.

Вот пример кода:
Код:
class Test
{
public:
static const float KValue=3.0;
Test();
};

Test::Test()
{
// Может быть в любой функции, необязательно в конструкторе
float foo = 1.0;
foo = qMax( foo, KValue );
}

int main()
{
// где-нибудь в программе
Test obj;
}

С другой стороны, при использовании обычных локальных констант в qMax (и подобных) всё проходит отлично.
Пример нормальной работы:
Код:
float foo = 1.0;
const float value = KValue; // Скопировать статическую константу в локальную
foo = qMax( foo, value );

Напишите, если кто знает из-за чего это происходит.

Используемая платформа:
Kubuntu 8.04
Qt 4.4.0 and 4.4.1
gcc 4.2.4
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #1 : Сентябрь 23, 2008, 15:55 »

qMin(), qMax(), qBound() здесь непричем. Вы пытаетесь инициализировать значением статический константный неинтегральный тип, а так делать нельзя. Только статические константные интегральные типы могут инициализироваться значением внутри класса.

Т.е. нужно писать так:

Код:
class Test
{
public:
static const float KValue;
Test();
};

const float Test::KValue = 3.0;
« Последнее редактирование: Сентябрь 23, 2008, 16:00 от pastor » Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
zavulon
Гость
« Ответ #2 : Сентябрь 23, 2008, 17:25 »

Огромное спасибо!
Действительно, в C++ простые типы данных делятся на две группы: целые (интегральные, integral) и нецелые. Целые типы имеют конечный и заранее известный набор значений: int, char, short, long и перечисления (enumerations). Все остальные, например float, double, char[], - это нецелые типы.

Вообще, в C++ в заголовке класса можно только объявлять статические константы. Опеределять их значение нужно уже вне объявления класса - как правило это .cpp - файл. Единственное исключение делается для целых (интегральных) типов - такие статические константы можно инициализировать сразу же при объявлении внутри класса. http://www.informit.com/blogs/blog.aspx?uk=30-C-Tips-in-30-Days-Tip-26-in-class-initialization-of-const-static-data-members-of-integral-types.

Поэтому, в данном случае с типом float не было так гладко. Но остается загадкой, почему мой второй вариант кода тогда работал? Т.е. когда static const float инициализируется внутри класса, а потом в каком-нибудь методе значение такой константы можно присвоить локальной переменной.
Записан
zavulon
Гость
« Ответ #3 : Сентябрь 23, 2008, 19:41 »

Становится все более интересно. Если float заменить на int, ничего не меняется. Компоновщик выдает ту же ошибку уже для целого типа.
Функции qMax() и др. реализованы как шаблоны, а аргументы передаются с помощью ссылок:
Код:
template<class T>
const T& qMax( const T& value1, const T& value2 );
Не в ссылках ли кроется загадка? На этапе компиляции все нормально. Ошибка происходит при компоновке. Т.е. функции qMax() явно не нравится, что ей передают адрес статической константы.
Если эту же константу передать в любую другую Qt-функцию, которая берет в качестве аргумента именно int или float (т.е. по значению), то все прекрасно работает.

Пример рабочего кода:
Код:
#include <QList>

class Test
{
public:
static const int KPos = 5;
Test();
QList< int > list;
};

Test::Test()
{
// Может быть в любой функции, необязательно в конструкторе
list.insert( KPos, 10 );   // Тут ок

/* А вот в этой строке будет ошибка:
int res = qMax(3, KPos);*/
}

int main()
{
// где-нибудь в программе
Test obj;
}
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #4 : Сентябрь 23, 2008, 20:15 »

Приведите полное сообщение об ошибке

//upd

Проверил код на MSVC2005, все работает нормально. Позже проверю под Линуксом
« Последнее редактирование: Сентябрь 23, 2008, 20:18 от pastor » Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
Alex03
Гость
« Ответ #5 : Сентябрь 24, 2008, 07:36 »

А у меня вот тут вопрос возник...
А чем отличаются в данном случае статическая и не статическая константы?
В случае:
Код:
class Test
{
...
    const float f = 5.0;
...
};
компилятор не будет в каждый объект засовывать константу... или будет?
Да и вообще есть ли точные правила когда константа обязательно представленна ячейкой памяти (и соответственно имеет свой адрес и т.д.), а когда может быть полностью соптипизированна (на той же x86 платформе тот же int проще константой в коде иметь, чем вытаскивать по адресу, порой ещё и не прямому).

Всё... пора идти за страуструпом (книга между домом и работой уже наверное месяц катается без дела).
Записан
zavulon
Гость
« Ответ #6 : Сентябрь 25, 2008, 16:29 »

Я пришел к выводу, что ошибка вызвана оптимизацией компилятора. Компилятор все константы, если это возможно, заменяет на числовые значения, которые естественно не имеют своего адреса. Попытка взять адрес такой константы в функции qMax(), приводит к ошибке. qMax(), qMin() и qBound() принимают аргументы по ссылке, а не по значению.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.052 секунд. Запросов: 23.