LINUX.ORG.RU

Дружба с глобальной функцией

 


0

3

Привет, вопрос элементарный, но что-то сообразить совсем не получается. Было примерно так (работало):

class Q {
   friend int main();
   Q() = default;
};

int main() {
   Q q;
}

Потом было добавлено namespace:

namespace NS {
class Q {
   friend int main();
   Q() = default;
};
} //NS

И теперь никак не удается назначить друга для Q из file scope. friend int main() не срабатывает (согласен), но также не помогает friend int ::main(), хотя на цппреференс есть пример:

friend class ::F; // friends the global F

Как правильно? Делать декларацию main в NS - не хочу. Компилятор выдает:

error: 'int main()' should have been declared inside '::'
   36 |  friend int ::main();
★★

Последнее исправление: pavlick (всего исправлений: 1)

Ответ на: комментарий от slovazap

Во-первых, не помогает

namespace NS {
int ::main();
         Definition or redeclaration of 'main' cannot name the global scope class T [clang: invalid_declarator_global_scope]
}

Во-вторых, friend int ::main() - и есть вполне достаточная декларация, зачем ее дублировать? Без namespace NS все работало, была forward декларация friend int main() в самом классе, никаких доп деклараций не требовалось.

pavlick ★★
() автор топика
Последнее исправление: pavlick (всего исправлений: 1)
Ответ на: комментарий от pavlick

Так все компилируется и работает

// Example program
#include <iostream>
#include <string>

int main();

namespace NS {
class Q {
   friend int ::main();
   Q() = default;
};
} //NS

int main()
{
    NS::Q q;
}

RyanGosling
()
Ответ на: комментарий от RyanGosling

Почему здесь не нужна forward декларация int main()? Здесь так работает, там иначе, алогично.

// Example program
#include <iostream>
#include <string>

//int main();  //-------------

//namespace NS {
class Q {
   friend int main();
   Q() = default;
};
//} //NS

int main()
{
    Q q;
}

pavlick ★★
() автор топика

Спс за ответы. Но я реально не въехал с какого черта при объявлении друга из глобального нейспейса нужна форвард декларация за пределами данного неймспейса, когда friend int ::main() должна быть достаточной опираясь на аналогичную ситуация, когда namespace отсутсвует.

pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

Может быть нельзя декларировать функции в одном нэймспейсе, находясь в другом? Насколько я помню, форвард декларация class foo::bar не работает, надо namespace foo { class bar; }

filosofia
()
Ответ на: комментарий от pavlick

А почему бы просто не сделать конструктор public? Или тебе принципиально нужно, чтобы именно через механизм друзей работало?

rumgot ★★★★★
()
Ответ на: комментарий от rumgot

Сделать можно, конечно, но хочется по максимуму наложить компайл тайм ограничений чтобы сам не накосячил через 1-2 месяца. Там вообще класс «пул потоков» глобальных для подключаемых модулей к софтине. Классический синглтон не подходит - пул нужно самым первым как создать, так и уничтожить. Поэтому сделал через дружбу с main, первым создаю, первым удаляю (до статиков).

pavlick ★★
() автор топика
Последнее исправление: pavlick (всего исправлений: 1)
Ответ на: комментарий от rumgot

Ну у нас ведь как со статиками? Порядок разрушения = обратному порядку создания. А это пул потоков, нужно гарантировано уничтожить его первым чтобы никакой лихой поток не дернул мертый объект. Как на 100% прогарантировать создание пула потоков последним? Может какой-нибудь статик дернет во время создания пул (вряд ли, но хз что мне в голову придет через два месяца). А так делаю глобальный укзатель на пул == nullptr, помещаю в него адрес первой строкой main, если кто раньше времени обратится, то получу segmentation fault

Pool *p = nullptr;
...
int main() {
   Pool pool; // лучше через unique_ptr, заюзать Deleter
   p = &pool;

   p = nullptr;
}

pavlick ★★
() автор топика
Последнее исправление: pavlick (всего исправлений: 1)
Ответ на: комментарий от pavlick

Ты можешь и по другому поступить, дать форвард на немспейс и класс в нем, с той лишь разницой что в виду того что это форвард придется работать с указателем, по вполне очевидной причине, что на момент использования в точке входа класса из немспейса еще нет, а указатель ради бога. В обратном случае (твоем) - точка входа в виде main уже есть и поэтому ты можешь юзать friend int ::main() из глобального немспейса с форвардом ранее.


// Example program
#include <iostream>
#include <string>

namespace NS { class Q; }

int main() {
    
    NS::Q *q;
    return 0;
}

namespace NS {

    class Q {
        friend int main();
        Q() = default;
    };
} //NS

anonymous
()
Ответ на: комментарий от pavlick

Так ты же можешь в функции, создающей/возвращающей синглтон создавать свой объект на куче:

static S* s = new S;
return s;

И все. Ответственность за удаление у вызывающего кода, т.е. в твоем случае у main(). Ну а создан он будет при первом вызове данной функции.

rumgot ★★★★★
()
Последнее исправление: rumgot (всего исправлений: 2)
Ответ на: комментарий от byko3y

оно аналогично и без немспейсов работает, он просто не понимает сути форвард декларации и того что это не определение, а лишь объявление, а с main финт ушами работает лишь потому что это main и потому как расположен код. Вот такой же пример без немспейса.



class Q;

int main() {
    
    Q *q;
    return 0;
}

class Q {
    friend int main();
    Q() = default;
};

anonymous
()
Ответ на: комментарий от pavlick

Без namespace NS все работало, была forward декларация friend int main() в самом классе, никаких доп деклараций не требовалось.

Ты просто привык. А так, то, что одно объявление — дружественной функции — является в некоторых случаях двумя объявлениями: собственно функции как дружественной и функции в неймспейсе, причём не делает имя видимым в том неймспейсе — выглядит искусственно (потому что и является таким).

utf8nowhere ★★★
()
Ответ на: комментарий от rumgot

Ну так то да, можно, но это размазывание ответственности какое-то, синглтон создал, а удаляет кто-то там другой, вот если бы он юник_птр возвращал (что невозможно в данном случае). Хочется красиво сделать, если все взлетит, то люди будут и модули дописывать, копаться в исходниках.

pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

Ну по поводу КРАСИВО: разве делать дружественную функцию main для того, чтобы создать такой объект - это красиво?

rumgot ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.