Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.71/7: Рейтинг темы: голосов - 7, средняя оценка - 4.71
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562

Как получить undefined reference вместо вывода?

10.08.2012, 11:18. Показов 1587. Ответов 8
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Была ситуация - объявлен класс - в нем оператор приведения к некому типу (указатель на функцию), оператор вывода в поток для этого класса определен в другом хедере. Если забыть подключить сей хедер - он выводил 0 или 1 в зависимости от возвращаемого значения оператором приведения (можно довольно сильно влететь не подключив файл).

Сейчас - объявлен класс - в нем оператор приведения к некому типу (указатель на функцию), прямого оператора вывода в поток для этого класса нет, есть класс для вывода, но это к теме не относится, объявленный аналогично в другом хедере, соответственно проблема остается.

А теперь вопрос.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
 
template<typename T>
class C
{
public:
   C():value(0)
   {
   }
   C(int v):value(v)
   {
   }
   typedef void (C::*unspecified_bool_type)();
private:
   void true_bool()
   {
   }
public:
   operator unspecified_bool_type()
   {
      return value ? &C::true_bool : 0;
   }
private:
   int value;
};
 
template<typename T>
std::ostream& operator << (std::ostream& os, typename C<T>::unspecified_bool_type);
 
int main()
{
   C<int> c;
   std::cout << c << std::endl;
   C<int> s(1);
   std::cout << s << std::endl;
}
Этот код работает. А хотелось бы получить undefined_reference.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
 
template<typename T>
class C
{
public:
   C():value(0)
   {
   }
   C(int v):value(v)
   {
   }
   typedef void (C::*unspecified_bool_type)();
private:
   void true_bool()
   {
   }
public:
   friend std::ostream& operator << (std::ostream& os, unspecified_bool_type);
   operator unspecified_bool_type()
   {
      return value ? &C::true_bool : 0;
   }
private:
   int value;
};
 
/*template<typename T>
std::ostream& operator << (std::ostream& os, typename C<T>::unspecified_bool_type);*/
 
int main()
{
   C<int> c;
   std::cout << c << std::endl;
   C<int> s(1);
   std::cout << s << std::endl;
}
Получаю undefined reference-ы как и надо, НО gcc сыплет ворнингами на тему

new.cpp:19:77: предупреждение: friend declaration «std::ostream& operator<<(std::ostream&, C<T>::unspecified_bool_type)» declares a non-template function [-Wnon-template-friend]
new.cpp:19:77: замечание: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
что не есть хорошо. Так же если объявить оператор вывода объявить свободным (но при этом указать просто C<T>) все тоже ок, получаю ошибки линковки как и хочу, но хотелось бы понять в чем конкретно проблема с первым случаем. (Про explicit операторы приведения знаю, юзать новый стандарт возможности нет). Желательно ткнуть в пункт стандарта, описывающий это поведение.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
10.08.2012, 11:18
Ответы с готовыми решениями:

Странная ошибка: [Linker error] undefined reference to `__dyn_tls_init_callback' [Linker error] undefined reference to ld returned 1 exit status
Здравствуйте. Вот недавно начал изучать книгу &quot;С++ для чайников&quot; Стефан Р. Девис 4-е издание. И напоролся на кучу ошибок) Но смог все...

Как исправить ошибку undefined reference to?
Изучаю Qt по книге Макса Шлее. В главе про работу с OpenGL приведён пример программы: OGlQuad.h #pragma once #include...

Undefined reference to
Много уже тем создано по даннму вопросу, но решения так и не нашел.. Есть конечно догадки, но как реализовать все равно не знаю. Прошу...

8
~ Эврика! ~
 Аватар для OhMyGodSoLong
1258 / 1007 / 74
Регистрация: 24.07.2012
Сообщений: 2,002
10.08.2012, 11:44
Я уж точно не помню, почему, но друзья шаблонных классов описываются вот так (19–20 строка). Но оно работает и не сыпет ошибками.
(чтоб не загромождать)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
 
template<typename T>
class C
{
public:
   C():value(0)
   {
   }
   C(int v):value(v)
   {
   }
   typedef void (C::*unspecified_bool_type)();
private:
   void true_bool()
   {
   }
public:
   template <class R>
   friend std::ostream& operator << (std::ostream& os, typename C<R>::unspecified_bool_type);
 
   operator unspecified_bool_type()
   {
      return value ? &C::true_bool : 0;
   }
private:
   int value;
};
 
/*template<typename T>
std::ostream& operator << (std::ostream& os, typename C<T>::unspecified_bool_type);*/
 
int main()
{
   C<int> c;
   std::cout << c << std::endl;
   C<int> s(1);
   std::cout << s << std::endl;
}

По идее дело в том, что каждый шаблонный класс — это отдельный класс. То есть нельзя объявить какую-то функцию другом сразу всех шаблонов, а надо тыкать носом в каждый из них (с помощью этого самого C<T>::).

Ща пойду читать бумажку.
0
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
10.08.2012, 11:46  [ТС]
~OhMyGodSoLong~, Да, это-то я вкурсе. Проблема в том, что этот код так же компилируется успешно, вместо того, чтобы давать undefined ref. http://liveworkspace.org/code/... 01dae8ace2
0
~ Эврика! ~
 Аватар для OhMyGodSoLong
1258 / 1007 / 74
Регистрация: 24.07.2012
Сообщений: 2,002
10.08.2012, 13:38
Лучший ответ Сообщение было отмечено ForEveR как решение

Решение

Ну пока я вижу, что он вообще не трогает эту функцию, а почему-то берёт какую-то дефолтную. Потому, естессно, никаких undefined reference на неиспользуемую несуществующую функцию. Посмотрев ещё на это и немного потыкав это всё в отладчике, он почему-то делает неявный каст к unspecified_bool_type, который void (*)(), а потом почему-то... приводит его к bool O_O

Ниччё не понимаю... Ну ладно первый каст. Но второй-то почему? Ну ладно, не нашёл функцию с void (*)(), значит приводим дальше. Но почему тогда к bool, а не int?

*яростно листает 13 главу про перегрузку*

Объяснить ругань в случае (с friend std::ostream& operator << (std::ostream& os, unspecified_bool_type);) ещё можно: C<int>::unspecified_bool_type и C<float>::unspecified_bool_type — это разные типы; так как объявление использует unspecified_bool_type из объявляемого класса C<T>, то он влепил спецификатор C<T>::; но сама функция-друг не объявлена шаблонной (функции-друзья же не являются методами классов), потому не имеет права использовать шаблонный тип T.

Добавлено через 46 минут
(Ссылки привожу по этой версии.)

Пример из 13.3.1.2/6
C++
1
2
3
4
5
6
7
8
struct A {
    operator int ();
};
A operator +( const A & , const A &);
void m () {
    A a , b ;
    a + b ; / / operator+(a,b) chosen over int(a) + int(b)
}
очень похож на эту проблему. Топаем на ссылаемый 13.3.3, где описывается способ выбора цепочки неявных преобразований типов при выборе перегруженного варианта функции.

Итого, у компилятора, когда он видит запись std::cout << c;, то, так как никакого
std::ostream& operator<<(std::ostream&, С<T>);
нет, то возникает выбор между пачкой неявных преобразований:
std::ostream& operator<<(std::ostream&, int);
std::ostream& operator<<(std::ostream&, bool);
std::ostream& operator<<(std::ostream&, С<T>::unspecified_bool_type);
и т. д.

В 13.3.3, 13.3.3.2 ногу свернуть можно.
Но, по видимому, он не считает преобразование к С<T>::unspecified_bool_type достаточным, потому как метод не определён, поэтому продолжает искать другие цепочки, чтобы выбрать какую-нибудь другую альтернативную перегрузку. И находит цепочку C<T> → С<T>::unspecified_bool_type ≡ void (*)() → bool. Последнее это стандартное правило из 4.12: указатель можно кастовать к bool. (И, естессно, так как неопределённый метод при такой цепочке преобразований не используется, то линковщик на него и не ругается.)

По-видимому, где-то так.

Не по теме:

В такие моменты прям отлично понимаешь, насколько C++ всё же монстр и сколько времени уходит на разработку его компиляторов.

1
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
10.08.2012, 14:01  [ТС]
Но, по видимому, он не считает преобразование к С<T>::unspecified_bool_type достаточным, потому как метод не определён, поэтому продолжает искать другие цепочки, чтобы выбрать какую-нибудь другую альтернативную перегрузку.
Несколько не понял вот этого. Что значит в данном контексте НЕ определен? Тогда почему работает, если класс не шаблонный?
0
~ Эврика! ~
 Аватар для OhMyGodSoLong
1258 / 1007 / 74
Регистрация: 24.07.2012
Сообщений: 2,002
10.08.2012, 15:02
Лучший ответ Сообщение было отмечено ForEveR как решение

Решение

Вот потому и «по-видимому». Я точно не уверен в семантике подобной записи, когда есть прототип функции (то есть компилятор знает, как её вызывать, и по идее может использовать), но нет реализации. По идее, это головная боль линкера — отыскать код функции по всем файлам.

Но откуда тогда компилятор знает, что кода нет, и выбрает вместо преобразования к C<T>::unspecified_bool_type, для которого как бы нет кода, другое преобразование, которое дольше (и без чтения 13.3.3.2 можно понять, что каст к юзер-тайпу лучше, чем каст к юзер-тайпу, а потом ещё каст к стандартному). Откуда он знает, что его нет?

Ведь действительно, если убрать шаблоны, то всё «не работает как надо». C → С::unspecified_bool_type ≡ void (*)() → bool не выбирается вместо C → С::unspecified_bool_type.

Возможно, тут как-то замешан вот этот пункт 14.5.3/4
When a function is defined in a friend function declaration in a class template, the function is instantiated when the function is used. The same restrictions on multiple declarations and definitions that apply to non-template function declarations and definitions also apply to these implicit definitions.
То есть если это не шаблонная функция, то она будет создана только при использовании. Возможно, выбор нужной перегрузки её поэтому и не видит, что она как бы не создана (потому что не используется). А нешаблонная функция создаётся вне зависимости от её использования.

Попробуем проверить. Есть такой код, он не ругается и выбирает цепочку до bool. А теперь такой. И тут ничего...

Тем более, что в 13.3.3.2 я что-то не увидел ничего про темплейты.

Единственное, что смущает, это 13.3.3/1, второй список, второй пункт. Там сказано, что нешаблонное лучше шаблонного. Но это только при условии, что обе цепочки равны по «хорошести».

Но есть ещё что-то в 13.3.3.1.2 про специальную трактовку юзер-кастов. Сейчас пытаюсь вкурить.

Добавлено через 14 минут
Что-то не разгорается.

В общем, пока что я могу сделать вывод, что неявные преобразования типов — это одно из величайших зол, которое внесли в C++. Избавились от пары лишних строчек при «очевидных» преобразованиях, зато можно запросто повеситься в пустой комнате.
1
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
10.08.2012, 15:50  [ТС]
~OhMyGodSoLong~, Ну да, теперь конечно есть explicit для user-defined conversions, но к сожалению нет возможности юзать С++11=(

Добавлено через 44 минуты
Как-то я протупил и оказалось все на самом деле довольно просто...

http://stackoverflow.com/quest... or-calling
1
~ Эврика! ~
 Аватар для OhMyGodSoLong
1258 / 1007 / 74
Регистрация: 24.07.2012
Сообщений: 2,002
10.08.2012, 15:57
Ага... Выводилка типов у C++ не такая крутая. Теперь ясно, чего оно его не считает за валидный конечный вариант приведения (тупо не видит), но видит через цепочку до bool. И чего без темплейтов всё окей.
1
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
10.08.2012, 16:01  [ТС]
~OhMyGodSoLong~, Ну да. У меня впринципе сразу была такая мысль как только этот код написал, но казалось, что если не может определить тип - будет ошибка, а тут оказывается еще целая цепочка конвертирования. Вообщем, спасибо, много нового узнал)
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
10.08.2012, 16:01
Помогаю со студенческими работами здесь

Undefined reference to
#include &lt;TXLib.h&gt; #include &lt;iostream&gt; using namespace std; void drawminion (int x4,int y4, int sdvig4,...

Undefined reference
/tmp/ccQRqGm4.o: In function `PoolAllocator::PoolAllocator(unsigned int, unsigned int)': PoolAllocator.cpp:(.text+0x14): undefined...

Undefined reference to
Извиняюсь на кривое создание темы. Случайно нажал Enter в заголовке. Фрагмент кода, где ругается(самая последняя строка). Использую...

Undefined reference to
Решил написать игру, поставил Audiere, а линковщик выдал: ...

undefined reference to
https://www.cyberforum.ru/qt/thread861722.html Не в том разделе создал тему, и поэтому даю линк на неё. Описание ошибки там же


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru