Форум программистов, компьютерный форум CyberForum.ru

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

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 1, средняя оценка - 5.00
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
10.08.2012, 11:18     Как получить undefined reference вместо вывода? #1
Была ситуация - объявлен класс - в нем оператор приведения к некому типу (указатель на функцию), оператор вывода в поток для этого класса определен в другом хедере. Если забыть подключить сей хедер - он выводил 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 операторы приведения знаю, юзать новый стандарт возможности нет). Желательно ткнуть в пункт стандарта, описывающий это поведение.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
10.08.2012, 11:18     Как получить undefined reference вместо вывода?
Посмотрите здесь:

C++ undefined reference...
C++ undefined reference
C++ undefined reference
C++ undefined reference to `A::a'
undefined reference to C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
10.08.2012, 11:44     Как получить undefined reference вместо вывода? #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>::).

Ща пойду читать бумажку.
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
10.08.2012, 11:46  [ТС]     Как получить undefined reference вместо вывода? #3
~OhMyGodSoLong~, Да, это-то я вкурсе. Проблема в том, что этот код так же компилируется успешно, вместо того, чтобы давать undefined ref. http://liveworkspace.org/code/38605d...7eec01dae8ace2
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
10.08.2012, 13:38     Как получить undefined reference вместо вывода? #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++ всё же монстр и сколько времени уходит на разработку его компиляторов.

ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
10.08.2012, 14:01  [ТС]     Как получить undefined reference вместо вывода? #5
Но, по видимому, он не считает преобразование к С<T>::unspecified_bool_type достаточным, потому как метод не определён, поэтому продолжает искать другие цепочки, чтобы выбрать какую-нибудь другую альтернативную перегрузку.
Несколько не понял вот этого. Что значит в данном контексте НЕ определен? Тогда почему работает, если класс не шаблонный?
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
10.08.2012, 15:02     Как получить undefined reference вместо вывода? #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++. Избавились от пары лишних строчек при «очевидных» преобразованиях, зато можно запросто повеситься в пустой комнате.
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
10.08.2012, 15:50  [ТС]     Как получить undefined reference вместо вывода? #7
~OhMyGodSoLong~, Ну да, теперь конечно есть explicit для user-defined conversions, но к сожалению нет возможности юзать С++11=(

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

http://stackoverflow.com/questions/1...erator-calling
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
10.08.2012, 15:57     Как получить undefined reference вместо вывода? #8
Ага... Выводилка типов у C++ не такая крутая. Теперь ясно, чего оно его не считает за валидный конечный вариант приведения (тупо не видит), но видит через цепочку до bool. И чего без темплейтов всё окей.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
10.08.2012, 16:01     Как получить undefined reference вместо вывода?
Еще ссылки по теме:

Undefined reference to C++
C++ Undefined reference to `GrPlot'
C++ Undefined reference to

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

Или воспользуйтесь поиском по форуму:
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
10.08.2012, 16:01  [ТС]     Как получить undefined reference вместо вывода? #9
~OhMyGodSoLong~, Ну да. У меня впринципе сразу была такая мысль как только этот код написал, но казалось, что если не может определить тип - будет ошибка, а тут оказывается еще целая цепочка конвертирования. Вообщем, спасибо, много нового узнал)
Yandex
Объявления
10.08.2012, 16:01     Как получить undefined reference вместо вывода?
Ответ Создать тему
Опции темы

Текущее время: 21:48. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru