Встроенная функция члена C ++ в файле .cpp

Я знаю, что встроенные функциичлены по определению должны войти в заголовок. Но что, если невозможно включить реализацию функции в заголовок? Возьмем эту ситуацию:

Файл Ah

#pragma once #include "Bh" class A{ B b; }; 

Файл Bh

 #pragma once class A; //forward declaration class B{ inline A getA(); }; 

В связи с циркуляром я должен поставить реализацию getA в

B.cpp

 #include "Bh" #include "Ah" inline AB::getA(){ return A(); } 

Будет ли компилятор inline getA ? Если это так, какое ключевое слово inline является значительным (в заголовке или в файле .cpp)? Есть ли другой способ поместить определение встроенной функции-члена в его .cpp-файл?

    Цитата из C ++ FAQ :

    Примечание. Обязательно, чтобы определение функции (часть между {…}) помещалось в файл заголовка, если только функция не используется только в одном файле .cpp. В частности, если вы поместите определение встроенной функции в файл .cpp и вы вызываете ее из какого-либо другого .cpp-файла, вы получите «неразрешенную внешнюю» ошибку из компоновщика.

    Компилятор должен видеть определение встроенной функции всякий раз, когда он находит какое-либо использование этой встроенной функции. Это обычно возможно, если встроенная функция помещается в файл заголовка.

    Будет ли компилятор inline getA?

    Нет, кроме случаев, когда использование getA() принадлежит самому B.cpp.

    Если это так, какое ключевое слово inline является значительным (одно в заголовке или в столбце cpp)?

    Лучшая практика : только в определении вне classа.

    Есть ли другой способ поместить определение встроенной функции-члена в его файл cpp?

    Нет, по крайней мере, я не знаю.

    Он не может, вне сферы действия B.cpp. Компилятор работает с базой для каждого компилятора, т. Е. Он компилирует каждый файл .cpp отдельно, поэтому, если он компилирует C.cpp, он не будет иметь код для getA () и ему потребуется выполнить вызов функции и (или, если это действительно заняло ваше слово и попыталось встроить его, оно закончится ошибкой компоновщика. inline имеет аналогичные свойства, такие как static ).

    Единственным исключением является LTCG, то есть генерация кода link-time, которая доступна для новых компиляторов.

    Одним из подходов в этом случае является наличие другого файла заголовка (иногда называемого * .inl-файлами), который содержит встроенный код.

    РЕДАКТИРОВАНИЕ. Что касается того, какая строка является актуальной – это одна в определении classа, то есть в файле заголовка. Имейте в виду, что многие компиляторы имеют свой собственный подход к тому, что может и должно быть встроено. Например, gcc может полностью отключить вложение (-O0), или он может встроить все, что он считает целесообразным, (например, -O3).

    Я бы сделал это в противоположном направлении.

    Не добавляйте встроенные объявления в свою функцию (если вам тоже не нужно).

    Единственный раз, когда вам нужно добавить объявление inline в функцию / метод, является определение функции в файле заголовка, но вне объявления classа.

    Xh

     class X { public: int getX() { return 4;} // No inline because it is part of the class. // The compiler knows that needs an inline tag int getY(); int getZ(); }; inline int X::getY() { return 5;} // This needs to be explicitly declared inline. // Otherwise the linker will complain about // multiple definitions in compilation units. 

    x.cpp

      // Never declare anything inline in the cpp file. int X::getZ() { return 6; } 

    Вам более конкретный случай.
    Удалите все встроенные спецификации. Они не делают то, что, по вашему мнению, делают.

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

    К тому времени, когда линкер добирается до него, не так много о встроенном статусе выхода компилятора, за исключением того, что компилятор будет отмечать определенные объекты как собираемые, например, потому что встроенная функция или экземпляр шаблона экземпляра появляется в нескольких единицах компиляции или он должен вызывать ошибку, когда несколько символов имеют общее имя, например, основная функция определяется дважды. Ничто из этого не влияет на фактический код, который он будет генерировать.

    Вот как я это сделал.

    Файл Ah

     #pragma once #include "Bh" class A { B b; }; 

    Файл Bh

     #pragma once class B { public: template inline T getA() { assert(NULL); // Use 'getA()' template specialization only! return NULL; } }; class A; // Forward declaration template<> inline AB::getA(); 

    Файл Ch

     #pragma once #include "Ah" #include "Bh" // Implement template specialization here! template<> inline AB::getA() { return A(); } 

    Просто включите файл «Ch», чтобы иметь возможность использовать метод getA (). Единственное изменение с исходным кодом заключается в том, что метод getA () должен быть определен как public, а не private.

    Однако, как многие из вас объяснили это, это не очень полезно.

    ISO / IEC 14882: 2014

    Каждая программа должна содержать ровно одно определение каждой не-встроенной функции или переменной, которая является odr-используемой в этой программе; не требуется диагностика. Определение может явно отображаться в программе, оно может быть найдено в стандартной или определяемой пользователем библиотеке или (если необходимо), оно неявно определено (см. 12.1, 12.4 и 12.8). Встроенная функция должна быть определена в каждой единицы перевода, в которой она используется odr.

    Давайте будем гением компьютера.