Re: Friend
От: artem.komisarenko Украина  
Дата: 08.08.13 12:11
Оценка: 24 (2) +4 :))) :)
Здравствуйте, Europe_cn, Вы писали:

E_>Прошу не сносить в холивар, так как вопрос касается C++


Да тут и холиварить-то не о чем. Если человек считает использование goto, friend, dynamic_cast, const_cast, reinterpret_cast, c-style cast, макросов нужное подчеркнуть плохим дизайном по определению, потому что прочитал об этом в каком-то там очередном блоге (со ссылкой в лучшем случае на Дейкстру, где тот говорил о Бейсике), значит он дурак по определению.
Re: Friend
От: igna Россия  
Дата: 08.08.13 08:43
Оценка: 6 (1) +4
Здравствуйте, Europe_cn, Вы писали:

E_>Интересует ваше мнение. Друг зло или нет? Как часто вам приходилось им пользоваться?


Использование friend нередко приводит к более естественному синтаксису:

class matrix {
    friend matrix mul(matrix const&, matrix const&);
    friend matrix inv(matrix const&);
    . . .
};

matrix a, b;

. . .

return mul(a, inv(b));


class matrix {
public:
    matrix mul(matrix const&) const;
    matrix inv() const;
    . . .
};

matrix a, b;

. . .

return a.mul(b.inv());


Возможно стоит всегда определять друга вместо члена, если не нужна виртуальность.
Re[2]: Friend
От: ioj Ниоткуда  
Дата: 08.08.13 11:46
Оценка: -2
Здравствуйте, igna, Вы писали:

I>Возможно стоит всегда определять друга вместо члена, если не нужна виртуальность.


нужно быть смелее, и переходить сразу к struct matrix с открытыми полями и набору ф-ций для работы с ней
нормально делай — нормально будет
Re[2]: Friend
От: Lorenzo_LAMAS  
Дата: 08.08.13 07:33
Оценка: 6 (1)
PM>
PM>friend void some_class::some_method();
PM>


PM>Не знаю, есть ли такое предложение в C++11/14


да уж что тут не знать, это есть сто лет в обед, поди с первых версий C-фронта было, никаких "высоко-технологичных" C++11 и не надо.
Of course, the code must be complete enough to compile and link.
Re: Friend
От: Tilir Россия http://tilir.livejournal.com
Дата: 08.08.13 07:10
Оценка: 4 (1)
Здравствуйте, Europe_cn, Вы писали:

E_>На одном собеседовании поспорил с собеседующим что "друг" обычно первый признок плохого дизайна. На что мне долго пытались втирать, что это хорошо, а в некоторых случаях необходимо. Нопример оператор вывода в поток (С++).

E_>Интересует ваше мнение. Друг зло или нет? Как часто вам приходилось им пользоваться?
E_>Прошу не сносить в холивар, так как вопрос касается C++.

1. Статическая дружба statefull классов вредна, т.к. нарушает инкапсуляцию.
2. Дружба класса с функцией сомнительна, но иногда упрощает разработку.
3. Но есть один сценарий, когда дружба крайне полезна. Дело в том, что в C++ друг статического родительского типа достаточен, чтобы делать дружественные вызовы полиморфных наследников. Звучит круто, да? =)

Синтетический пример:

class Parent
{
  friend class Family;
  protected:
    virtual void Answer() = 0;
};

class Child : public Parent
{
  private:
    void Answer() { printf("Child!\n"); }
    int encapsulated;
};

class Family
{
  public:
    void ParentAnswer(Parent *p) { p->Answer(); } /* ok */
    #if 0
      void ChildAnswer(Child *c) { c->Answer(); } /* error! */
      int breakEncapsulation(Child *c) { return c->encapsulated; } /* error again! */
    #endif
};

int test(void)
{
  Child c;
  Family f;
  f.ParentAnswer(&c); /* ok, Child->answer will be called */
  return 0;
}


Обратите внимание: Child статически не дружит с Family и его инкапсуляция не нарушена. Parent -- stateless там нечего нарушать. Но при этом, Family может вызывать закрытые методы класса Child если они полиморфны в его Parent.

Как мне кажется, ради подобных фишек дружба и оставлена в объектной модели C++. Ну ещё можно вспомнить Barton-Nackman trick, но он уже не актуален.
Re[4]: Friend
От: ioj Ниоткуда  
Дата: 08.08.13 14:35
Оценка: :)
Здравствуйте, igna, Вы писали:

I>Зачем?


чтобы не плодить сущности сверх необходимого
нормально делай — нормально будет
Re[5]: Friend
От: Evgeny.Panasyuk Россия  
Дата: 08.08.13 14:50
Оценка: +1
Здравствуйте, ioj, Вы писали:

EP>>В class matrix обычно vector<Scalar> storage; + информация о размерностях, которая вместе с размером storage составляют инвариант, который нельзя рушить.

ioj>я не хочу скатываться в холивар а-ля anemic vs rich, просто по мне выбор класс + френды для операций вместо свободных ф-ций и простой структуры выглядит несколько странным.

Почему? friend'ы класса указываются в нём самом — они точно такие же члены его интерфейса (которые имеют доступ к инвариантам) как и member functions — основное отличие в синтаксисе использования.
Причём синтаксис non-member более общий чем member.
Например можно сделать функцию inverse и для double и для matrix:
double x = ...;
Matrix y = .../
auto z = inverse(value);
auto solution = inverse(y) * b;


Посмотри например Notes on Programming Степанова:

While we could make a member function to return length, it is better to make it a global friend function. If we do that, we will be able eventually to define the same function to work on built-in arrays and achieve greater uniformity of design. I made size into a member function in STL in an attempt to please the standard committee. I knew that begin, end and size should be global functions but was not willing to risk another fight with the committee. In general, there were many compromises of which I am ashamed. It would have been harder to succeed without making them, but I still get a metallic taste in my mouth when I encounter all the things that I did wrong while knowing full how to do them right.

Там class fvector_int, у которого данные private, и есть
friend std::size_t size(const fvector_int& x)


То что мы даём доступ к инвариантам класса некоторым функциям через friend — не означает, что мы даём его всем.
Re[2]: Friend
От: Europe_cn  
Дата: 08.08.13 15:04
Оценка: -1
Здравствуйте, artem.komisarenko, Вы писали:

Сечёшь разницу между "первый признок плохого дизайна" и плохим дизайном по определению есть?

Все конструкции были добавлены в язык по объективным причинам, но не все конструкции нужно использовать при первом удобном случае.
Re[5]: Friend
От: igna Россия  
Дата: 08.08.13 15:22
Оценка: +1
Здравствуйте, ioj, Вы писали:

ioj>чтобы не плодить сущности сверх необходимого


Так и проверку типов можно отменить. Чтобы не плодить.
Re[5]: Friend
От: Stanislav V. Zudin Россия  
Дата: 08.08.13 15:37
Оценка: +1
Здравствуйте, Europe_cn, Вы писали:

E_>>>Все конструкции были добавлены в язык по объективным причинам, но не все конструкции нужно использовать при первом удобном случае.


SVZ>>А при втором удобном случае можно?

SVZ>>Где граница?

E_>Границы нет по определению. Главное чтобы аргументация была. Одну и ту же фичу можно реализовать по разному. И стоимость поддержки будет тоже разная.

E_>Весь код тоже можно в main запихнуть.

Вот именно.
Качество дизайна можно оценить по стоимости сопровождения этого кода. Но никак не по используемым в нем языковым конструкциям.
Но если ты это понимаешь, зачем вообще завел этот топик? И зачем устроил спор с собеседующим? Спор ради спора? Бесполезная трата времени.
_____________________
С уважением,
Stanislav V. Zudin
Re[5]: Friend
От: Tilir Россия http://tilir.livejournal.com
Дата: 13.08.13 08:41
Оценка: -1
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>То есть теперь "доказательство" вредности исключений строится не на том что "goto = зло", exceptions похожи на goto, exceptions = зло, а на том что "non-local-control-flow = зло" ...? То же самое только в профиль


Здесь сложно что-то "доказать", речь о стиле и опыте. Человек проще воспринимает локальные конструкции. В своё время именно переход от GOTO к осмысленным IF, WHILE, etc сильно упростил промышленное программирование. Потом придумали threads и exceptions и стало всё как раньше =)

Предпочтение к локальным конструкциям улучшает структурность программы, её поддерживаемость и модифицируемость. Это также облегчает анализ и трансформации в бэкенде компилятора.

EP>Например, со-процедуры зло? А ведь они "мощнее" исключений, так как позволяют прыгать по стэку и вверх и вниз. И да — некоторые задачи отлично выражаются в терминах сопроцедур. Или другой пример — async/await из последнего C#, которые стали одной из любимых фишек шарпистов. Самый обыкновенный non-local-control-flow. Так что — тоже зло?


Я не люблю спорить на эти темы. Здесь я всё излагаю довольно ясно, кмк: http://rsdn.ru/forum/philosophy/5109064.1
Автор: Tilir
Дата: 22.03.13
Friend
От: Europe_cn  
Дата: 08.08.13 06:20
Оценка:
На одном собеседовании поспорил с собеседующим что "друг" обычно первый признок плохого дизайна. На что мне долго пытались втирать, что это хорошо, а в некоторых случаях необходимо. Нопример оператор вывода в поток (С++).

Интересует ваше мнение. Друг зло или нет? Как часто вам приходилось им пользоваться?

Прошу не сносить в холивар, так как вопрос касается C++.
friend c++
Re: Friend
От: PM  
Дата: 08.08.13 06:56
Оценка:
E_>На одном собеседовании поспорил с собеседующим что "друг" обычно первый признок плохого дизайна. На что мне долго пытались втирать, что это хорошо, а в некоторых случаях необходимо. Нопример оператор вывода в поток (С++).

E_>Интересует ваше мнение. Друг зло или нет? Как часто вам приходилось им пользоваться?


Даже у типичного интроверта-программиста могут быть друзья

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

friend void some_class::some_method();


Не знаю, есть ли такое предложение в C++11/14

Друзья ввода/вывод в поток в принципе не нужны, если есть такое:


class some_class
{
public:
   void print(std::ostream& os) const;
   void read(std::istream& is);
};

std::ostream& operator<<(std::ostream& os, some_class const& obj)
{
   obj.print(os);
   return os;
}

std::istream& operator>>(std::istream& os, some_class& obj)
{
   obj.read(is);
   return is;
}


С другой стороны, можно написать чуть короче

class some_class
{
public:
    friend std::ostream& operator<<(std::ostream& os, some_class const& obj)
    {
        // реализация print(os);
       return os;
    }

    friend std::istream& operator>>(std::istream& os, some_class& obj)
    {
        // реализация read(is);
        return is;
    }
};


Мне кажется это вопрос вкуса.

В общем, как обычно, у явления дружбы есть и преимущества, и недостатки.
Re: Friend
От: Stanislav V. Zudin Россия  
Дата: 08.08.13 08:05
Оценка:
Здравствуйте, Europe_cn, Вы писали:

E_>На одном собеседовании поспорил с собеседующим что "друг" обычно первый признок плохого дизайна. На что мне долго пытались втирать, что это хорошо, а в некоторых случаях необходимо. Нопример оператор вывода в поток (С++).


E_>Интересует ваше мнение. Друг зло или нет? Как часто вам приходилось им пользоваться?


Пример: Контейнер и итераторы для обхода этого контейнера.
Вполне разумно итераторы сделать "друзьями", ибо все вместе они составляют единую систему.
_____________________
С уважением,
Stanislav V. Zudin
Re[3]: Friend
От: PM  
Дата: 08.08.13 08:06
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

PM>>
PM>>friend void some_class::some_method();
PM>>


PM>>Не знаю, есть ли такое предложение в C++11/14


L_L>да уж что тут не знать, это есть сто лет в обед, поди с первых версий C-фронта было, никаких "высоко-технологичных" C++11 и не надо.


Спасибо, действительно не знал Но не работает для еще не объявленных целиком классов, а именно такой случай мне реально требуется:

class A;

class B
{
    friend A::A(); // error C2027: use of undefined type 'A'
private:
    B() {}
};

class A
{
    A() {}
    B b;
};

A a;


И не поспоришь, действительно тип A еще не объявлен.
Re[3]: Friend
От: igna Россия  
Дата: 08.08.13 11:49
Оценка:
Здравствуйте, ioj, Вы писали:

ioj>нужно быть смелее, и переходить сразу к struct matrix с открытыми полями и набору ф-ций для работы с ней


Зачем?
Re[3]: Friend
От: Evgeny.Panasyuk Россия  
Дата: 08.08.13 12:54
Оценка:
Здравствуйте, ioj, Вы писали:

I>>Возможно стоит всегда определять друга вместо члена, если не нужна виртуальность.

ioj>нужно быть смелее, и переходить сразу к struct matrix с открытыми полями и набору ф-ций для работы с ней

В class matrix обычно vector<Scalar> storage; + информация о размерностях, которая вместе с размером storage составляют инвариант, который нельзя рушить.
Re[2]: Friend
От: Evgeny.Panasyuk Россия  
Дата: 08.08.13 13:13
Оценка:
Здравствуйте, artem.komisarenko, Вы писали:

AK>Да тут и холиварить-то не о чем. Если человек считает использование goto, friend, dynamic_cast, const_cast, reinterpret_cast, c-style cast, макросов нужное подчеркнуть плохим дизайном по определению, потому что прочитал об этом в каком-то там очередном блоге (со ссылкой в лучшем случае на Дейкстру, где тот говорил о Бейсике), значит он дурак по определению.


+1
Некоторые даже пытаются через свою фанатичную веру в то что какая-то конструкция является плохой по определению, доказать что другие конструкции которые сводятся к этим, которые "плохие по определению", тоже являются плохими.

Недавно на одном из форумов так в очередной раз пытались "доказать" вредность исключений — типа это аналог goto, соответственно исключения — это "плохо":

> throw is a way to put GOTO in your code, the more you see throw or catch , the more your code is full of flaw.

и соответственно мой ответ:

By using your "GOTO" reasoning we can go even further — we can consider harmful even "if" statements. Because at lowest level "if" statement translates into something like:

if(condition) goto label; // jne, brne, etc

So, by using your conclusions: "the more you see if statement, the more your code is full of flaw" — how funny is that?

Moreover, the greatest of us actually claim that there is no syntactic limitations in semantic questions, and goto is useful. Prohibiting it fanatically for all cases is not a good idea.
Alexander Stepanov shows how goto statement can be useful:
http://www.youtube.com/watch?v=mrtaApqAjA8&amp;t=5m38s
http://books.google.com/books?id=CO9ULZGINlsC&amp;lpg=PT209&amp;ots=Ow3EbqSBqA&amp;dq=elements+of+programming+split_linked&amp;hl=en&amp;pg=PT210

Re[4]: Friend
От: ioj Ниоткуда  
Дата: 08.08.13 14:40
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:


EP>В class matrix обычно vector<Scalar> storage; + информация о размерностях, которая вместе с размером storage составляют инвариант, который нельзя рушить.


я не хочу скатываться в холивар а-ля anemic vs rich, просто по мне выбор класс + френды для операций вместо свободных ф-ций и простой структуры выглядит несколько странным.
нормально делай — нормально будет
Re[3]: Friend
От: Evgeny.Panasyuk Россия  
Дата: 08.08.13 15:15
Оценка:
Здравствуйте, Europe_cn, Вы писали:

E_>Здравствуйте, artem.komisarenko, Вы писали:

E_>Сечёшь разницу между "первый признок плохого дизайна" и плохим дизайном по определению есть?

Лучше расскажи нам про разницу между "первый признок плохого дизайна" и "Друг зло или нет?"

E_>Интересует ваше мнение. Друг зло или нет? Как часто вам приходилось им пользоваться?

Re[3]: Friend
От: Stanislav V. Zudin Россия  
Дата: 08.08.13 15:15
Оценка:
Здравствуйте, Europe_cn, Вы писали:

E_>Все конструкции были добавлены в язык по объективным причинам, но не все конструкции нужно использовать при первом удобном случае.


А при втором удобном случае можно?
Где граница?
_____________________
С уважением,
Stanislav V. Zudin
Re[4]: Friend
От: Europe_cn  
Дата: 08.08.13 15:31
Оценка:
Здравствуйте, Stanislav V. Zudin, Вы писали:

SVZ>Здравствуйте, Europe_cn, Вы писали:


E_>>Все конструкции были добавлены в язык по объективным причинам, но не все конструкции нужно использовать при первом удобном случае.


SVZ>А при втором удобном случае можно?

SVZ>Где граница?

Границы нет по определению. Главное чтобы аргументация была. Одну и ту же фичу можно реализовать по разному. И стоимость поддержки будет тоже разная.
Весь код тоже можно в main запихнуть.
Re[6]: Friend
От: ioj Ниоткуда  
Дата: 08.08.13 15:35
Оценка:
Здравствуйте, igna, Вы писали:

ioj>>чтобы не плодить сущности сверх необходимого


I>Так и проверку типов можно отменить. Чтобы не плодить.


ключевые слова: сверх необходимого.
нормально делай — нормально будет
Re[6]: Friend
От: ioj Ниоткуда  
Дата: 08.08.13 15:43
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:


EP>То что мы даём доступ к инвариантам класса некоторым функциям через friend — не означает, что мы даём его всем.


я может не совсем понятно выразился. я не ратую за класс с мемберами, я предлагаю использовать структуру с открытыми полями + набор функций, проверка инвариантов пусть будет внутри ф-ций.
нормально делай — нормально будет
Re[7]: Friend
От: Evgeny.Panasyuk Россия  
Дата: 08.08.13 15:50
Оценка:
Здравствуйте, ioj, Вы писали:

EP>>То что мы даём доступ к инвариантам класса некоторым функциям через friend — не означает, что мы даём его всем.

ioj>я может не совсем понятно выразился. я не ратую за класс с мемберами, я предлагаю использовать структуру с открытыми полями + набор функций, проверка инвариантов пусть будет внутри ф-ций.

Ок, возьмём vector_int:
keyword vector_int
{
    int *first, *last, *last_allocated;
//...
};

Чтобы ты выбрал? struct or class?
Re[8]: Friend
От: ioj Ниоткуда  
Дата: 08.08.13 17:00
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Чтобы ты выбрал? struct or class?


class, но у вектора нет операций а-ля mul(matrix, matrix), т.е. синтаксически операции с вектором не порождают уродливые конструкции
нормально делай — нормально будет
Re[9]: Friend
От: Evgeny.Panasyuk Россия  
Дата: 08.08.13 17:07
Оценка:
Здравствуйте, ioj, Вы писали:

EP>>Чтобы ты выбрал? struct or class?

ioj>class, но у вектора нет операций а-ля mul(matrix, matrix), т.е. синтаксически операции с вектором не порождают уродливые конструкции

А если у вектора был такой size:
friend std::size_t size(const vector_int& x)

то была бы struct?

На счёт матрицы тоже не понятно — у неё ведь тоже есть инвариант, зачем делать его открытым?
class Matrix
{
    vector<Scalar> storage;
    size_t width;
    
    void invariant()
    {
        assert( size(storage) % width == 0  );
    }
// ...
}
Re[10]: Friend
От: ioj Ниоткуда  
Дата: 08.08.13 17:55
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>А если у вектора был такой size:

EP>
EP>friend std::size_t size(const vector_int& x)
EP>

EP>то была бы struct?
нет, см. ниже про matrix

EP>На счёт матрицы тоже не понятно — у неё ведь тоже есть инвариант, зачем делать его открытым?

потому что по идее у матрицы кроме конструктора методы не нарушают инвариант
нормально делай — нормально будет
Re[11]: Friend
От: Evgeny.Panasyuk Россия  
Дата: 08.08.13 18:22
Оценка:
Здравствуйте, ioj, Вы писали:

EP>>На счёт матрицы тоже не понятно — у неё ведь тоже есть инвариант, зачем делать его открытым?

ioj>потому что по идее у матрицы кроме конструктора методы не нарушают инвариант

не пойму что ты имеешь ввиду.

Возьмём матрицу выше, допустим сделали её struct с конструктором который устанавливает правильный инвариант.
Можно написать внешний код, который сломает инвариант:
Matrix x = ... ;
// ...
x.width = 2;
x.storage.resize(3);

Почему бы не запретить это, сделав матрицу классом?
Re[12]: Friend
От: ioj Ниоткуда  
Дата: 08.08.13 20:30
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Почему бы не запретить это, сделав матрицу классом?


да пусть нарушает, если это делается, то это очень нужно и инвариант в любом случае был бы нарушен, добавлением метода али ещё чего, поэтому если инвариант будет чекаться как предусловие в нужных функциях, то особой проблемы я не вижу.
нормально делай — нормально будет
Re[13]: Friend
От: Evgeny.Panasyuk Россия  
Дата: 08.08.13 22:00
Оценка:
Здравствуйте, ioj, Вы писали:

EP>>Почему бы не запретить это, сделав матрицу классом?

ioj>да пусть нарушает, если это делается, то это очень нужно

1. Если действительно нужно — то скорей всего у матрицы плохой интерфейс, в смысле не хватает чего-то нужного.
2. Я не пойму почему твоя позиция отличается для member и non-member friend — пусть и в случае member'ов всё будет public

ioj>и инвариант в любом случае был бы нарушен, добавлением метода али ещё чего,


мне трудно представить code review который пропустит добавление метода, например, в std::vector

ioj>поэтому если инвариант будет чекаться как предусловие в нужных функциях, то особой проблемы я не вижу.


Чекаться в Release, или только Debug?
Re[3]: Friend
От: Tilir Россия http://tilir.livejournal.com
Дата: 09.08.13 07:12
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>By using your "GOTO" reasoning we can go even further — we can consider harmful even "if" statements. Because at lowest level "if" statement translates into something like:

if(condition) goto label; // jne, brne, etc


До вас пытались донести простую мысль, что throw как и goto (собственно -- в большей степени чем goto, так что throw -- ГОРАЗДО хуже) создаёт нелокальный control-flow. Во что всё это транслируется в ассемблере не так важно (а вы вообще уверены, что ваш if доживёт до ассемблера и не будет куда-нибудь спропагирован по дороге?), а вот разница между локальным и нелокальным потоком управления в программе это очень серьёзно. Потому что ассемблер читает пара упоротых реверсеров, а вот лапшу из goto и исключений, читает и модифицирует каждый второй, и знаете, бывает волосы встают дыбом не только на голове.
Re[6]: Friend
От: Erop Россия  
Дата: 11.08.13 06:20
Оценка:
Здравствуйте, igna, Вы писали:

I>Так и проверку типов можно отменить. Чтобы не плодить.


Дык мегамодный JS знаешь?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Friend
От: sokel Россия  
Дата: 12.08.13 08:50
Оценка:
Здравствуйте, Europe_cn, Вы писали:

E_>На одном собеседовании поспорил с собеседующим что "друг" обычно первый признок плохого дизайна. На что мне долго пытались втирать, что это хорошо, а в некоторых случаях необходимо. Нопример оператор вывода в поток (С++).


E_>Интересует ваше мнение. Друг зло или нет? Как часто вам приходилось им пользоваться?


E_>Прошу не сносить в холивар, так как вопрос касается C++.


Использую для функторов с pointer-to-member доступом к данным.

Например по простому компараторы объявлять, вроде такого: member_order<foo, int, &foo::bar, less<int> >.
Если foo::bar инкапсулировать, так по простому уже не получается, bar доступен только через getter, а getter если в шаблон засовывать, то через указатель на функцию, совсем не эффективно.
Ну и friend в этом случае вполне ok если лямбд нет:

class foo
{
    friend class foo_traits;
public:
    int bar() const { return bar_; }
private:
    int bar_;
};

class foo_traits
{
    typedef member_order<foo, int, &foo::bar_> foo_bar_order;
};


Теоретически всё решалось бы публичным объявлением шаблонного компаратора внутре foo, но MSVC в отличе от gcc к сожалению не ест pointer-to-member для незавершенных классов (внутри самого класса).
Re[7]: Friend
От: Erop Россия  
Дата: 12.08.13 11:21
Оценка:
Здравствуйте, ioj, Вы писали:

ioj>я может не совсем понятно выразился. я не ратую за класс с мемберами, я предлагаю использовать структуру с открытыми полями + набор функций, проверка инвариантов пусть будет внутри ф-ций.


Что в тыоей позиции понятно? -- То, что так, как ты предлагаешь можно написать хорошую, в общем поддерживаемую программу.

А вот что не понтно, так это то, зачем это делать на С++...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Friend
От: Erop Россия  
Дата: 12.08.13 13:44
Оценка:
Здравствуйте, sokel, Вы писали:

S>Использую для функторов с pointer-to-member доступом к данным.


Ну это же просто обход дырки в языке/компиляторе, а не систематический подход?
На самом деле сама по себе модель доступа к атрибутам объекта в С++ довольно убогая.
Скажем лично мне часто не хватает возможности предоставить публичный КОНСТАНТНЫЙ доступ.
С другой стороны это дело довольно элементарно обходится, например так:
class ZZZ {
    int bar1;
    int bar2;
    int bar3;
public:
    struct Accessor {
        const int& bar1;
        const int& bar2;
        const int& bar3;
        Accessor( const ZZZ& theThis ) : 
            bar1(theThis.bar1 ), 
            bar2(theThis.bar2 ),  
            bar3(theThis.bar3 ) 
                {}
    };
};

int qqqZZZ( ZZZ& oZzz )
{
    ZZZ::Accessor o( oZzz );
    // o.bar1 = 5; // не скомпилируется!
    return o.bar2;
}
только, на мой вкус, надо это очень редко, и можно как-то проще, ну более по-С-шному код зарефакторить в этом месте и всё...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Friend
От: Evgeny.Panasyuk Россия  
Дата: 12.08.13 14:55
Оценка:
Здравствуйте, Erop, Вы писали:

E>С другой стороны это дело довольно элементарно обходится, например так:
class ZZZ {


можно намного проще:
class Widget
{
    struct Data
    {
        int foo, bar;
    } data = {0, 1};
public:
    const Data &access() const
    {
        return data;
    }
};
 
int main()
{
    Widget x;
    // ERROR: x.access().bar = 5;
    return x.access().foo;
}

+ сахар по вкусу.
Re[4]: Friend
От: Evgeny.Panasyuk Россия  
Дата: 12.08.13 15:36
Оценка:
Здравствуйте, Tilir, Вы писали:

T>До вас пытались донести простую мысль, что throw как и goto (собственно -- в большей степени чем goto, так что throw -- ГОРАЗДО хуже) создаёт нелокальный control-flow.


То есть теперь "доказательство" вредности исключений строится не на том что "goto = зло", exceptions похожи на goto, exceptions = зло, а на том что "non-local-control-flow = зло" ...? То же самое только в профиль

Почему non-local-control-flow считается злом априори? Если целевая задача наиболее красиво и эффективно выражается с помощью нелокальных переходов — то зачем их стеснятся?

Например, со-процедуры зло? А ведь они "мощнее" исключений, так как позволяют прыгать по стэку и вверх и вниз. И да — некоторые задачи отлично выражаются в терминах сопроцедур.

Или другой пример — async/await из последнего C#, которые стали одной из любимых фишек шарпистов. Самый обыкновенный non-local-control-flow. Так что — тоже зло?

T>Во что всё это транслируется в ассемблере не так важно (а вы вообще уверены, что ваш if доживёт до ассемблера и не будет куда-нибудь спропагирован по дороге?),


Что-то может и не дожить — if(true) скорей всего не доживёт, только что это меняет?

T>а вот разница между локальным и нелокальным потоком управления в программе это очень серьёзно. Потому что ассемблер читает пара упоротых реверсеров, а вот лапшу из goto и исключений, читает и модифицирует каждый второй, и знаете, бывает волосы встают дыбом не только на голове.


Волосы могут встать дыбом от кода содержащего любую синтаксическую конструкцию. Код становится плохим не от того что он использует какой-то синтаксис
Re[3]: Friend
От: sokel Россия  
Дата: 12.08.13 16:27
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, sokel, Вы писали:


S>>Использую для функторов с pointer-to-member доступом к данным.


E>Ну это же просто обход дырки в языке/компиляторе, а не систематический подход?


Кстати, вот ещё вариант когда friend может быть полезен — использование CRTP с открытием деталей реализации для базы:
template<typename impl>
class base
{
public:
    void foo() { static_cast<impl&>(*this).bar(); }
};

class impl : public base<impl>
{
    friend class base<impl>;
private:
    void bar() {}
};
Re[4]: Friend
От: Lonely Dog Россия  
Дата: 12.08.13 16:39
Оценка:
Здравствуйте, sokel, Вы писали:


S>Кстати, вот ещё вариант когда friend может быть полезен — использование CRTP с открытием деталей реализации для базы:

Очень часто использую friend именно для этой цели. Например, так:
class CMyDialog : CDialogImpl<CMyDialog>
{
public:
BOOL Show(HWND Parent);

private:
friend class CDialogImpl<CMyDialog>;
BEGIN_MSG_MAP_EX(CMyDialog)
END_MSG_MAP()
};
Re[4]: Friend
От: Erop Россия  
Дата: 12.08.13 17:52
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

E>>С другой стороны это дело довольно элементарно обходится, например так:
class ZZZ {


EP>можно намного проще:

Это ++11, но тут это не суть. Суть в том, что access публикует потроха, "для всех", а через спец. структуру мы публикуем только для тех, кто эту структуру строит => легко найти весь тесно связанный с потрохами код

EP>+ сахар по вкусу.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: Friend
От: Evgeny.Panasyuk Россия  
Дата: 12.08.13 18:06
Оценка:
Здравствуйте, Erop, Вы писали:

E>>>С другой стороны это дело довольно элементарно обходится, например так:
class ZZZ {

EP>>можно намного проще:
E>Это ++11, но тут это не суть.

Кроме in-class initialization, что там C++11?

E>Суть в том, что access публикует потроха, "для всех", а через спец. структуру мы публикуем только для тех, кто эту структуру строит => легко найти весь тесно связанный с потрохами код


Спец структуру/функцию, которая будет давать доступ, можно сделать и в моём случае — я же сказал, "сахар по вкусу". А разница в том, что не надо пробрасывать каждое поле вручную.
Да и .access() — тоже легко найти.
Re[6]: Friend
От: Erop Россия  
Дата: 13.08.13 02:04
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Кроме in-class initialization, что там C++11?

Оно самое.


EP>Спец структуру/функцию, которая будет давать доступ, можно сделать и в моём случае — я же сказал, "сахар по вкусу". А разница в том, что не надо пробрасывать каждое поле вручную.

EP>Да и .access() — тоже легко найти.
Да, это я тупанул. Не заметил, что ты приватные поля в структуру собрал. Так, конечно, тое можно, если мы только свои поля публикуем.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Friend
От: sokel Россия  
Дата: 13.08.13 07:43
Оценка:
Здравствуйте, Erop, Вы писали:

E>Ну это же просто обход дырки в языке/компиляторе, а не систематический подход?


А вот ещё вариант когда реально нужен friend: intrusive_ptr.
Аналогично операторам вывода в поток используется ADL для выбора нужной ф-ции intrusive_ptr_add_ref/release. И если в случае с выводом в поток действительно можно обойтись public функцией типа print, то add_ref/release желательно закрыть.

class foo
{
private:
    friend void intrusive_ptr_add_ref(foo* obj) {}
    friend void intrusive_ptr_release(foo* obj) {}
};
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.