Правильные пацаны юзают правильные касты? :)
От: oziro Нигерия  
Дата: 15.01.08 16:51
Оценка:
Привет

Разглядывая boost::intrusive_ptr, заметил там

// ...
typedef intrusive_ptr this_type; 

// ...
    intrusive_ptr & operator=(intrusive_ptr const & rhs)
    {
        this_type(rhs).swap(*this); // const_cast ???
        return *this;
    }

    intrusive_ptr & operator=(T * rhs)
    {
        this_type(rhs).swap(*this); // static_cast ???
        return *this;
    }

// ...


Что это: лень, здоровый прагматизм или просто до первого багфикса оставили?
В shared_ptr, кстати, *_cast'ы везде.
Re: Правильные пацаны юзают правильные касты? :)
От: rg45 СССР  
Дата: 15.01.08 16:58
Оценка: 5 (2)
Здравствуйте, oziro, Вы писали:

O>Привет


O>Разглядывая boost::intrusive_ptr, заметил там


O>
O>        this_type(rhs).swap(*this); // const_cast ???
O>


O>Что это: лень, здоровый прагматизм или просто до первого багфикса оставили?


А зачем тут const_cast? Выражение this_type(rhs) создает временный объект, который хоть и является rvalue, но для него по стандарту можно вызывать неконстантные методы, в данном случае — swap. Ну а выражению *this const_cast и подавно не нужен — это lvalue.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: Правильные пацаны юзают правильные касты? :)
От: oziro Нигерия  
Дата: 15.01.08 17:10
Оценка:
Здравствуйте, rg45, Вы писали:

O>>
O>>        this_type(rhs).swap(*this); // const_cast ???
O>>


R>Выражение this_type(rhs) создает временный объект, который хоть и является rvalue, но для него по стандарту можно вызывать неконстантные методы, в данном случае — swap.


Во как! Это я и не подумал. Считал, что вызывается метод swap у rhs, а не у временного объекта. Мозгодробительно, имхо.
Re[3]: Правильные пацаны юзают правильные касты? :)
От: Кодёнок  
Дата: 16.01.08 08:09
Оценка: :))
Здравствуйте, oziro, Вы писали:

O>Во как! Это я и не подумал. Считал, что вызывается метод swap у rhs, а не у временного объекта. Мозгодробительно, имхо.


Но это же одно из самых замечательных свойств С++! Вот тебе еще пример: сколько звездочек выведет программа?

#include <stdio.h>

struct A { 
  A(...) {
    printf("*");
  }
};

int main()
{
   A three(666, 666, 666);
   A two(666, 666);
   A one(666);
   A zero();
}
Re[3]: Правильные пацаны юзают правильные касты? :)
От: Аноним  
Дата: 16.01.08 12:30
Оценка:
O>Во как! Это я и не подумал. Считал, что вызывается метод swap у rhs, а не у временного объекта. Мозгодробительно, имхо.
Это exception-safety. Потому так и пишут.
Re[4]: Правильные пацаны юзают правильные касты? :)
От: dotidot Россия  
Дата: 16.01.08 15:05
Оценка: +2
Здравствуйте, Кодёнок, Вы писали:

Кё>Но это же одно из самых замечательных свойств С++! Вот тебе еще пример: сколько звездочек выведет программа?


Кё>
Кё>#include <stdio.h>

Кё>struct A { 
Кё>  A(...) {
Кё>    printf("*");
Кё>  }
Кё>};

Кё>int main()
Кё>{
Кё>   A three(666, 666, 666);
Кё>   A two(666, 666);
Кё>   A one(666);
Кё>   A zero();
Кё>}
Кё>


я что-то не пойму. А как объявление функции в теле функции и вызов метода у временных объектов связаны?
Re[4]: Правильные пацаны юзают правильные касты? :)
От: Аноним  
Дата: 16.01.08 15:26
Оценка:
Здравствуйте, Кодёнок, Вы писали:

Кё>Здравствуйте, oziro, Вы писали:


O>>Во как! Это я и не подумал. Считал, что вызывается метод swap у rhs, а не у временного объекта. Мозгодробительно, имхо.


Кё>Но это же одно из самых замечательных свойств С++! Вот тебе еще пример: сколько звездочек выведет программа?


Кё>
Кё>#include <stdio.h>

Кё>struct A { 
Кё>  A(...) {
Кё>    printf("*");
Кё>  }
Кё>};

Кё>int main()
Кё>{
Кё>   A three(666, 666, 666);
Кё>   A two(666, 666);
Кё>   A one(666);
Кё>   A zero();
Кё>}
Кё>


а почему вы решили, что определение конструктора с переменным числом параметров определяет также конструктор по-умолчанию?
Re[5]: Правильные пацаны юзают правильные касты? :)
От: Аноним  
Дата: 16.01.08 15:31
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Кодёнок, Вы писали:


Кё>>Здравствуйте, oziro, Вы писали:


А>а почему вы решили, что определение конструктора с переменным числом параметров определяет также конструктор по-умолчанию?


более того, то же относится и к конструктору копирования, который должен быть определен явно, а не опосредованно (включая и шаблонные конструкторы)
Re[5]: Правильные пацаны юзают правильные касты? :)
От: rg45 СССР  
Дата: 16.01.08 15:45
Оценка: +2
Здравствуйте, <Аноним>, Вы писали:

А>Здравствуйте, Кодёнок, Вы писали:


Кё>>Здравствуйте, oziro, Вы писали:


O>>>Во как! Это я и не подумал. Считал, что вызывается метод swap у rhs, а не у временного объекта. Мозгодробительно, имхо.


Кё>>Но это же одно из самых замечательных свойств С++! Вот тебе еще пример: сколько звездочек выведет программа?


Кё>>
Кё>>#include <stdio.h>

Кё>>struct A { 
Кё>>  A(...) {
Кё>>    printf("*");
Кё>>  }
Кё>>};

Кё>>int main()
Кё>>{
Кё>>   A three(666, 666, 666);
Кё>>   A two(666, 666);
Кё>>   A one(666);
Кё>>   A zero();
Кё>>}
Кё>>


А>а почему вы решили, что определение конструктора с переменным числом параметров определяет также конструктор по-умолчанию?


Тут ведь главная замануха-то в чем: выражение A zero(); не создает переменную с именем zero, а объявляет функцию с именем zero и результатом типа A!.
Но каким образом это связано с топиком, я не понял
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: Правильные пацаны юзают правильные касты? :)
От: IROV..  
Дата: 16.01.08 16:39
Оценка:
Здравствуйте, Аноним, Вы писали:

O>>Во как! Это я и не подумал. Считал, что вызывается метод swap у rhs, а не у временного объекта. Мозгодробительно, имхо.

А>Это exception-safety. Потому так и пишут.

а кому плюсы? )))
я не волшебник, я только учусь!
Re: Правильные пацаны юзают правильные касты? :)
От: skeptik_  
Дата: 17.01.08 00:16
Оценка:
Здравствуйте, oziro, Вы писали:

O>Что это: лень, здоровый прагматизм или просто до первого багфикса оставили?

O>В shared_ptr, кстати, *_cast'ы везде.

Это стандартная идиома имплементации оператора присвоения. Ребята просто строчку решили съэкономить.
Re[6]: Правильные пацаны юзают правильные касты? :)
От: Кодёнок  
Дата: 17.01.08 06:38
Оценка: 15 (4) :)))
Здравствуйте, rg45, Вы писали:

R>Тут ведь главная замануха-то в чем: выражение A zero(); не создает переменную с именем zero, а объявляет функцию с именем zero и результатом типа A!.


Именно. А конструктор по умолчанию тут ни при чем, как аноним написал.

Но это я между прочим самый простой случай привел, для 1-го класса! Бывает и хуже ведь

#include <stdio.h>

struct A { 
  A(...) {
    printf("*");
  }
};

template <class T> struct Main : public T
{
    static void Run()
    {
        A x(T::foo);
    }
};

struct Ansi {
    typedef int foo;
};

struct Unicode {
    enum { foo };
};

int main()
{
    Main<Ansi>::Run();
    Main<Unicode>::Run();
}


Сколько звездочек выведется? Вы всё еще любите С++?

R>Но каким образом это связано с топиком, я не понял


Просто поддержал разговором комментарий «мозгодробительно»
Re[7]: Правильные пацаны юзают правильные касты? :)
От: rg45 СССР  
Дата: 17.01.08 08:26
Оценка:
Здравствуйте, Кодёнок, Вы писали:

Кё>Здравствуйте, rg45, Вы писали:


R>>Тут ведь главная замануха-то в чем: выражение A zero(); не создает переменную с именем zero, а объявляет функцию с именем zero и результатом типа A!.


Кё>Именно. А конструктор по умолчанию тут ни при чем, как аноним написал.


Кё>Но это я между прочим самый простой случай привел, для 1-го класса! Бывает и хуже ведь


Кё>
Кё>#include <stdio.h>

Кё>struct A { 
Кё>  A(...) {
Кё>    printf("*");
Кё>  }
Кё>};

Кё>template <class T> struct Main : public T
Кё>{
Кё>    static void Run()
Кё>    {
Кё>        A x(T::foo);
Кё>    }
Кё>};

Кё>struct Ansi {
Кё>    typedef int foo;
Кё>};

Кё>struct Unicode {
Кё>    enum { foo };
Кё>};

Кё>int main()
Кё>{
Кё>    Main<Ansi>::Run();
Кё>    Main<Unicode>::Run();
Кё>}
Кё>


Кё>Сколько звездочек выведется? Вы всё еще любите С++?


Ну, впринципе, все тоже самое, только похитрей завернуто. В инстанцировании c классом Unicode выражение A x(T::foo); определяет переменную с именем x, а с классом Ansi — объявляет функцию, поскольку Ansi::foo — это тип. Одно непонятно, как во втором случае компилятор обходится без ключевого слова typename?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[5]: Правильные пацаны юзают правильные касты? :)
От: Аноним  
Дата: 17.01.08 08:44
Оценка:
IRO>а кому плюсы? )))
Да ладно Сбереги для более интересного случая
Re[8]: Правильные пацаны юзают правильные касты? :)
От: Lorenzo_LAMAS  
Дата: 18.01.08 08:49
Оценка:
Можно еще немножко "углУбить" пример и посмотреть, как кретински колбасит комеау:

#include <stdio.h>

struct A { 
  A(...) {
    printf("*");
  }
//  int operator ()(){return 0;} //(1)
};

template <class T> struct Main : public T
{
    static void Run()
    {
        A x(T::foo);
        x();
    }
};

struct Ansi {
    typedef int foo;
};

struct Unicode {
    enum { foo };
};

int main()
{
    Main<Ansi>::Run();
}


Здесь комо орет так:

"ComeauTest.c", line 15: error: call of an object of a class type without
appropriate operator() or conversion functions to
pointer-to-function type
x();
^

"ComeauTest.c", line 15: error: too few arguments in function call
x();
^

Т.е., похоже, он сам не определился, объект это или функция. Дальше больше, если все раскомментировать оператор (1), то ругань поменяется:

"ComeauTest.c", line 15: error: too few arguments in function call
x();
^
detected during instantiation of "void Main<T>::Run() [with T=Ansi]"
at line 29

1 error detected in the compilation of "ComeauTest.c".

Of course, the code must be complete enough to compile and link.
Re[9]: Правильные пацаны юзают правильные касты? :)
От: Lorenzo_LAMAS  
Дата: 18.01.08 08:51
Оценка:
Впрочем, можно его и еще развить дальше. Добавить аргумент в вызов:

#include <stdio.h>

struct A { 
  A(...) {
    printf("*");
  }
  int operator ()(){return 0;}
};

template <class T> struct Main : public T
{
    static void Run()
    {
        A x(T::foo);
        x(1);
    }
};

struct Ansi {
    typedef int foo;
};

int main()
{
    Main<Ansi>::Run();
}


и тут:

"ComeauTest.c", line 15: error: no instance of function "A::operator()" matches the
argument list
The argument types that you used are: (int)
object type is: A
x(1);
^

1 error detected in the compilation of "ComeauTest.c".

Of course, the code must be complete enough to compile and link.
Re[9]: Правильные пацаны юзают правильные касты? :)
От: rg45 СССР  
Дата: 18.01.08 09:10
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>Можно еще немножко "углУбить" пример и посмотреть, как кретински колбасит комеау:


L_L>
L_L>#include <stdio.h>

L_L>struct A { 
L_L>  A(...) {
L_L>    printf("*");
L_L>  }
L_L>//  int operator ()(){return 0;} //(1)
L_L>};

L_L>template <class T> struct Main : public T
L_L>{
L_L>    static void Run()здесь
L_L>    {
L_L>        A x(T::foo);
L_L>        x();
L_L>    }
L_L>};

L_L>struct Ansi {
L_L>    typedef int foo;
L_L>};

L_L>struct Unicode {
L_L>    enum { foo };
L_L>};

L_L>int main()
L_L>{
L_L>    Main<Ansi>::Run();
L_L>}
L_L>


L_L>Здесь комо орет так:

L_L>

L_L>"ComeauTest.c", line 15: error: call of an object of a class type without
L_L> appropriate operator() or conversion functions to
L_L> pointer-to-function type
L_L> x();
L_L> ^

L_L>"ComeauTest.c", line 15: error: too few arguments in function call
L_L> x();
L_L> ^


Так все правильно, в случае, Main<Unicode> выражение: A x(T::foo); инстанцирется как объявление функции x, которая принимает один параметр типа T::foo, а значит и вызывать x надо с параметром типа T::foo. Причем тут есть один нюанс: если попытаться в качестве аргумента подставить значение, не зависящее от параметра шаблона (например 123), то он ругается даже при отсутствии вообще каких либо инстанцирований этого шаблона — еще на первой фазе компиляции. А вот если сделать вызов и передать в качестве параметра выражение, зависящее от параметра: x(T::foo());, то компилируется без ошибок. Причем, совершенно зря компилируется, потому, что не должно. Если попробовать написать рядышком выражение: typedef A y(T::foo);, то он сразу же одупляет, что это объявление функции и начинает требовать ключевое слово typename.

Ура! Мы нашли баг в Comeau-online!
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[10]: Правильные пацаны юзают правильные касты? :)
От: Lorenzo_LAMAS  
Дата: 18.01.08 09:22
Оценка:
Мне кажется, баг там есть. A x(T::foo); компилятор должен понимать однозначно — как объект. Т.е. т.к. нет typename, то T::foo это не тип. А вот что происходит, когда T::foo оказывается типом, мне непонятно. И почему он ссылается на дурацкий оператор operator () () в классе А — мне тоже непонятно. Если сделать так

#include <stdio.h>

struct A { 
  A(...) {
    printf("*");
  }
private:
  int operator ()(int){return 0;}
};

template <class T> struct Main : public T
{
    static void Run()
    {
        A x(T::foo);
        x(1);
    }
};

struct Ansi {
    typedef int foo;
};

int main()
{
    Main<Ansi>::Run();
}


То комеау вообще все нравится и он считает x — функцией с одним целочисленным параметром. А вот если убрать оператор () из класса А или поменять его сигнатуру — то тут комо опять ругается.
Of course, the code must be complete enough to compile and link.
Re[11]: Правильные пацаны юзают правильные касты? :)
От: rg45 СССР  
Дата: 18.01.08 09:24
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>Мне кажется, баг там есть. A x(T::foo); компилятор должен понимать однозначно — как объект. Т.е. т.к. нет typename, то T::foo это не тип. А вот что происходит, когда T::foo оказывается типом, мне непонятно. И почему он ссылается на дурацкий оператор operator () () в классе А — мне тоже непонятно. Если сделать так


L_L>
L_L>#include <stdio.h>

L_L>struct A { 
L_L>  A(...) {
L_L>    printf("*");
L_L>  }
L_L>private:
L_L>  int operator ()(int){return 0;}
L_L>};

L_L>template <class T> struct Main : public T
L_L>{
L_L>    static void Run()
L_L>    {
L_L>        A x(T::foo);
L_L>        x(1);
L_L>    }
L_L>};

L_L>struct Ansi {
L_L>    typedef int foo;
L_L>};

L_L>int main()
L_L>{
L_L>    Main<Ansi>::Run();
L_L>}
L_L>


L_L>То комеау вообще все нравится и он считает x — функцией с одним целочисленным параметром. А вот если убрать оператор () из класса А или поменять его сигнатуру — то тут комо опять ругается.


Да нет же! Именно функция! Вот это компилируется без ошибок:
#include <stdio.h>

struct A { 
  A(...) {
    printf("*");
  }
};

template <class T> struct Main : public T
{
    static void Run()
    {
        A x(T::foo);
        typedef A Y(typename T::foo);
        Y* y = x;
        y(123);
    }
};

struct Ansi {
    typedef int foo;
};

int main()
{
    Main<Ansi>::Run();
}

Это баг Comeau-online!!!
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[12]: Правильные пацаны юзают правильные касты? :)
От: Lorenzo_LAMAS  
Дата: 18.01.08 09:30
Оценка:
R>Да нет же! Именно функция! Вот это компилируется без ошибок:
Я не согласен, и возможно, не прав. Как мне кажется синтаксис — вещь фиксированная. Если есть какая-то конструкция, то выбираться должно однозначно — объявление ли это объекта, или объявление функции. Ты же сам видел, без всех твоих добавленных фокусов с указателями и т.п. — комо что-то говорил про оператор ().
Of course, the code must be complete enough to compile and link.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.