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

Непонятки с конвертацией типов - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 10, средняя оценка - 4.70
yekka
384 / 148 / 8
Регистрация: 12.05.2011
Сообщений: 450
01.07.2012, 20:27     Непонятки с конвертацией типов #1
Краткое описание примера. Определен класс Foo, единственное поле которого -- константная ссылка (const std::string &).
В классе определены лишь конструктор с сигнатурой Foo(const std::string &) и оператор конвертации обратно в константную ссылку на строку.
C++
1
2
3
4
5
6
7
8
class Foo {
  public:
    typedef const std::string & ValT;
    Foo(const std::string & _str) : str(_str) {}
    operator ValT() { return str; }
  private:
    ValT str;
};
  1. Строим объект foo класса Foo, конвертируем его в (const std::string &) и распечатываем:
    C++
    1
    2
    3
    
    std::string str("abcdef");
    Foo foo(str);
    std::cout << (const std::string &) foo << std::endl;
    Посмотреть результат компиляции
    Все отлично компилируется и работает как задумано.
  2. Теперь же попробуем перед печатью конвертнуть объект foo в (std::string &) (т.е. без const):
    C++
    1
    
    std::cout << (std::string &) foo << std::endl;
    Посмотреть результат компиляции
    Компилятор все прожевывает, компилирует, но при попытке исполнить получившийся бинарник выводится куча мусора вместо ожидаемой строки.
    Output limit exceeded. Application output is limited to 10240 symbols

Теперь вопросы:
  1. Почему вообще во втором случае компиляция оказывается успешной? Как компилятор умудряется конвертировать объект типа Foo в (std::string&), если для этого типа определена только конвертация в тип (const std::string &)?
  2. И как объяснить результат выполнения полученного бинарника? Т.е. даже если предположить, что компилятор тупо начхал на спецификатор const и просто использовал const std::string & как std::string &, то, казалось бы, все равно должна бы была вывестись та же самая строка "abcdef". Но на деле все совсем не так.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
gray_fox
What a waste!
 Аватар для gray_fox
1246 / 1129 / 54
Регистрация: 21.04.2012
Сообщений: 2,354
Завершенные тесты: 3
01.07.2012, 20:48     Непонятки с конвертацией типов #2
Цитата Сообщение от yekka Посмотреть сообщение
Почему вообще во втором случае компиляция оказывается успешной? Как компилятор умудряется конвертировать объект типа Foo в (std::string&), если для этого типа определена только конвертация в тип (const std::string &)?
Ну ведь
Цитата Сообщение от yekka Посмотреть сообщение
C++
1
(std::string &) foo
- это явное приведение, ответственнонсть за последствия уже не на компиляторе. С неявным так не выйдет:
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
#include <iostream>
#include <string>
 
 
struct foo {
   
   foo(std::string const& string) : string(string) {}
   
   operator std::string const&() const {
      return string;
   }
 
private:
   std::string const& string;
};
 
 
int main() {
    std::string string("something");
    foo object(string);
    
    std::string const& constRef = object;
    std::cout << constRef << std::endl;
    
    // should fail
    // std::string & mutableRef = object;
    // std::cout << mutableRef << std::endl;
}
http://liveworkspace.org/code/a2e31e...f5f98109e10391
yekka
384 / 148 / 8
Регистрация: 12.05.2011
Сообщений: 450
01.07.2012, 21:01  [ТС]     Непонятки с конвертацией типов #3
а я почему-то был уверен, что явное приведение типов ограничивается только возможностями static_cast и reinterpret_cast, которые константность менять не могут. но сейчас проверил, оказалось, что я ошибался.
gray_fox
What a waste!
 Аватар для gray_fox
1246 / 1129 / 54
Регистрация: 21.04.2012
Сообщений: 2,354
Завершенные тесты: 3
01.07.2012, 21:13     Непонятки с конвертацией типов #4
Цитата Сообщение от yekka Посмотреть сообщение
я почему-то был уверен, что явное приведение типов ограничивается только возможностями static_cast и reinterpret_cast
По моему лучше вообще не пользоваться C-style cast в C++, как минимум, так константность можно снять только с помощью const_cast .
yekka
384 / 148 / 8
Регистрация: 12.05.2011
Сообщений: 450
01.07.2012, 21:22  [ТС]     Непонятки с конвертацией типов #5
походу возник еще один вопрос
допустим, мы хотим писать
C++
1
std::cout << foo << std::endl
то получаем ошибку, суть которой в том, что оператор << определен для целых чисел, для чисел с плавающей точкой, для указателей и для манипуляторов и ни в один из этих типов Foo конвертировать нельзя.
Результат компиляции
Ну и если добавить в класс Foo operator float(), то все действительно без проблем компилируется:
http://liveworkspace.org/code/b80a2a...407f3fbd4dd823

Но вот непонятно, почему компилятору не видна версия operator<< для строк. Ведь такая версия есть.
Можно было бы предположить, что оператор << для строк объявлен как шаблонная ф-ция, не имеющая общего определения, но имеющая только специализации для конкретных типов, но тогда бы ошибка была бы другой, что-то вроде undefined reference to...
ForEveR
Модератор
Эксперт С++
 Аватар для ForEveR
7955 / 4717 / 318
Регистрация: 24.06.2010
Сообщений: 10,525
Завершенные тесты: 3
03.07.2012, 16:51     Непонятки с конвертацией типов #6
yekka, Видна.

In file included from include/c++/4.7.1/string:54:0,
from include/c++/4.7.1/bits/locale_classes.h:42,
from include/c++/4.7.1/bits/ios_base.h:43,
from include/c++/4.7.1/ios:43,
from include/c++/4.7.1/ostream:40,
from include/c++/4.7.1/iostream:40,
from source.cpp:1:
include/c++/4.7.1/bits/basic_string.h:2750:5: note: template<class _CharT, class _Traits, class _Alloc> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::basic_string<_CharT, _Traits, _Alloc>&)
include/c++/4.7.1/bits/basic_string.h:2750:5: note: template argument deduction/substitution failed:
source.cpp:17:18: note: 'Foo' is not derived from 'const std::basic_string<_CharT, _Traits, _Alloc>'
Кстати при явном преобразовании все ок. http://liveworkspace.org/code/fee52f...9db6ba7c310315

Добавлено через 33 минуты
http://liveworkspace.org/code/372e0c...13d3ec99f77a97

Вообщем довольно странный расклад. Он не может конвертнуть к шаблонному типу, почитаю стандарт поищу, в разделе 12.2.3 про это ничего нет. Может и gcc косячит.

Добавлено через 2 часа 14 минут
Расклад такой.
http://stackoverflow.com/questions/1...sion-operators

Добавлено через 11 минут
Итого для работы того кода достаточно сделать так.

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
#include <iostream>
#include <string>
 
std::ostream& operator << (std::ostream& os, const std::basic_string<char>& obj)
{
   return std::operator << (os, obj);
}
 
class Test
{
public:
   explicit Test(const std::string& s_):s(s_)
   {
   }
   operator std::string() const { return s; }
private:
   std::string s;
};
 
int main()
{
   Test t("Hello");
   std::cout << t << std::endl;
}
http://liveworkspace.org/code/4d892c...18487c796294de
yekka
384 / 148 / 8
Регистрация: 12.05.2011
Сообщений: 450
03.07.2012, 18:53  [ТС]     Непонятки с конвертацией типов #7
когда перекрываются перегруженные функции, шаблонные функции и их специализации, получается крайне неочевидные результаты

статья в тему -- http://www.gotw.ca/publications/mill17.htm
ForEveR
Модератор
Эксперт С++
 Аватар для ForEveR
7955 / 4717 / 318
Регистрация: 24.06.2010
Сообщений: 10,525
Завершенные тесты: 3
03.07.2012, 19:20     Непонятки с конвертацией типов #8
yekka, В представленном выше коде нет никаких специализаций и неочевидного ничего здесь нет, ибо в варианты попадают все операторы <<, объявленные в хедер-файлах в области видимости пространства имен std + глобальная область видимость, в std есть оператор вывода для string, но он шаблонный, в глобальной же области видимости оператор не шаблонный, следовательно он и выбирается.
yekka
384 / 148 / 8
Регистрация: 12.05.2011
Сообщений: 450
03.07.2012, 22:45  [ТС]     Непонятки с конвертацией типов #9
Сегодня 16:51
Цитата Сообщение от ForEveR Посмотреть сообщение
Вообщем довольно странный расклад. Он не может конвертнуть к шаблонному типу, почитаю стандарт поищу, в разделе 12.2.3 про это ничего нет. Может и gcc косячит.
Сегодня 19:20
Цитата Сообщение от ForEveR Посмотреть сообщение
неочевидного ничего здесь нет



Тем не менее, не понятно, почему в случае
http://liveworkspace.org/code/1d2155...2fb8ee6adf3e81
бьется память, а, казалось бы, аналогичный вариант с const_cast и static_cast
http://liveworkspace.org/code/72751c...4b6a13a51ba7a3
исправно работает?

Как выяснилось, первом случае генерится код с точностью до хеша совпадающий с вот этим вариантом, использующим const_cast и reinterpret_cast:
http://liveworkspace.org/code/87d226...4b51d42d069f0d
Остается только разобраться, почему здесь компилятором используется reinterpret_cast, а не static_cast
ForEveR
Модератор
Эксперт С++
 Аватар для ForEveR
7955 / 4717 / 318
Регистрация: 24.06.2010
Сообщений: 10,525
Завершенные тесты: 3
04.07.2012, 00:12     Непонятки с конвертацией типов #10
yekka, Я про последний свой код говорил)
Что делает приведение типов в стиле С: пытается использовать static_cast, если не получается, использует reinterpret_cast. Далее, если нужно, использует const_cast .
Jupiter
Каратель
Эксперт C++
6545 / 3965 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
04.07.2012, 00:16     Непонятки с конвертацией типов #11
Цитата Сообщение от yekka Посмотреть сообщение
а, казалось бы, аналогичный вариант с const_cast и static_cast
http://liveworkspace.org/code/72751c...4b6a13a51ba7a3
исправно работает?
что-то таки const_cast делает, непросто ж так его ввели

Не по теме:

ещё один довод в пользу кастов

yekka
384 / 148 / 8
Регистрация: 12.05.2011
Сообщений: 450
04.07.2012, 07:42  [ТС]     Непонятки с конвертацией типов #12
Цитата Сообщение от ForEveR Посмотреть сообщение
Что делает приведение типов в стиле С: пытается использовать static_cast, если не получается, использует reinterpret_cast. Далее, если нужно, использует const_cast .
ну так об том и речь. в данном случае вполне достаточно static_cast'а, но компилятор почему-то использует reinterpret_cast
silent_1991
Эксперт C++
4945 / 3021 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
04.07.2012, 12:40     Непонятки с конвертацией типов #13
yekka, потому что не надо, как уже говорили, использовать каст в С-стиле.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
05.07.2012, 20:55     Непонятки с конвертацией типов
Еще ссылки по теме:

C++ непонятки с for
C++ Linux Непонятки с Valgrind
C++ Непонятки с выводом
Непонятки с DLL C++ WinAPI

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

Или воспользуйтесь поиском по форуму:
yekka
384 / 148 / 8
Регистрация: 12.05.2011
Сообщений: 450
05.07.2012, 20:55  [ТС]     Непонятки с конвертацией типов #14
Цитата Сообщение от silent_1991 Посмотреть сообщение
yekka, потому что не надо, как уже говорили, использовать каст в С-стиле.

Не по теме:

ну если нечего сказать по делу, то зачем же флудить-то?



что-то не могу понять.
с одной стороны, стандарт явно утверждает, что при c-style приведении типов комбинация const_cast + reinterpret_cast должна использоваться только в том случае, когда const_cast + static_cast не справляются.
с другой стороны, и gcc, и clang в данном случае (http://liveworkspace.org/code/1d2155...2fb8ee6adf3e81) используют reinterpret_cast
Yandex
Объявления
05.07.2012, 20:55     Непонятки с конвертацией типов
Ответ Создать тему
Опции темы

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