Форум программистов, компьютерный форум, киберфорум
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 1, средняя оценка - 5.00
ForEveR
В астрале
Эксперт С++
7994 / 4753 / 321
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
#1

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

10.08.2012, 11:18. Просмотров 785. Ответов 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
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
10.08.2012, 11:18
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Как получить undefined reference вместо вывода? (C++):

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

undefined reference... - C++
Добрый день.На C перешел совсем недавно,поэтому могу не знать всех тонкостей.Подскажите,в какую сторону копать для исправления следующей...

undefined reference to `A::a' - C++
//==========================================================================================================================================...

undefined reference - C++
Пытаюсь разобраться с Box2D. Выпадает куча ошибок типа undefined reference to `b2World::b2World(b2Vec2 const&amp;)'| Box2D.h файл...

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

Undefined reference to - C++
Помогите, пожалуйста. Нужно было написать программу с использованием шаблона. Появляется ошибка &quot;undefined reference to...

8
OhMyGodSoLong
~ Эврика! ~
1245 / 994 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
10.08.2012, 11:44 #2
Я уж точно не помню, почему, но друзья шаблонных классов описываются вот так (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
В астрале
Эксперт С++
7994 / 4753 / 321
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
10.08.2012, 11:46  [ТС] #3
~OhMyGodSoLong~, Да, это-то я вкурсе. Проблема в том, что этот код так же компилируется успешно, вместо того, чтобы давать undefined ref. http://liveworkspace.org/code/38605dc1d0f70faa707eec01dae8ace2
0
OhMyGodSoLong
~ Эврика! ~
1245 / 994 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
10.08.2012, 13:38 #4
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
Ну пока я вижу, что он вообще не трогает эту функцию, а почему-то берёт какую-то дефолтную. Потому, естессно, никаких 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
В астрале
Эксперт С++
7994 / 4753 / 321
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
10.08.2012, 14:01  [ТС] #5
Но, по видимому, он не считает преобразование к С<T>::unspecified_bool_type достаточным, потому как метод не определён, поэтому продолжает искать другие цепочки, чтобы выбрать какую-нибудь другую альтернативную перегрузку.
Несколько не понял вот этого. Что значит в данном контексте НЕ определен? Тогда почему работает, если класс не шаблонный?
0
OhMyGodSoLong
~ Эврика! ~
1245 / 994 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
10.08.2012, 15:02 #6
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
Вот потому и «по-видимому». Я точно не уверен в семантике подобной записи, когда есть прототип функции (то есть компилятор знает, как её вызывать, и по идее может использовать), но нет реализации. По идее, это головная боль линкера — отыскать код функции по всем файлам.

Но откуда тогда компилятор знает, что кода нет, и выбрает вместо преобразования к 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
В астрале
Эксперт С++
7994 / 4753 / 321
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
10.08.2012, 15:50  [ТС] #7
~OhMyGodSoLong~, Ну да, теперь конечно есть explicit для user-defined conversions, но к сожалению нет возможности юзать С++11=(

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

http://stackoverflow.com/questions/1...erator-calling
1
OhMyGodSoLong
~ Эврика! ~
1245 / 994 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
10.08.2012, 15:57 #8
Ага... Выводилка типов у C++ не такая крутая. Теперь ясно, чего оно его не считает за валидный конечный вариант приведения (тупо не видит), но видит через цепочку до bool. И чего без темплейтов всё окей.
1
ForEveR
В астрале
Эксперт С++
7994 / 4753 / 321
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
10.08.2012, 16:01  [ТС] #9
~OhMyGodSoLong~, Ну да. У меня впринципе сразу была такая мысль как только этот код написал, но казалось, что если не может определить тип - будет ошибка, а тут оказывается еще целая цепочка конвертирования. Вообщем, спасибо, много нового узнал)
0
10.08.2012, 16:01
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
10.08.2012, 16:01
Привет! Вот еще темы с ответами:

Undefined reference to - C++
Есть класс NavyPort. Его заголовок: #ifndef NAVYPORT_H #define NAVYPORT_H class NavyPort { public: NavyPort(bool...

Undefined reference to - C++
Matrix.h #pragma once #include &lt;iostream&gt; template &lt;typename T&gt; class Matrix { private: int n1, n2; T **mas; public:...

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

undefined reference - C++
Доброго времени суток! Есть следующий код: #include &lt;iostream&gt; using namespace std; enum direction {Up, Down, Left, Right}; ...


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

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru