Почему невозможно встроить определения функций в файл .cpp?

Почему невозможно встроить определения функций или функций-членов класса в файлы .cpp? Например, в моих тестовых примерах ниже компоновщик вернет мне ошибку undefined reference, если я попытаюсь встроить определение функции или члена класса в файл cpp:

test.h

void print();

class A
{
    public:
        void print() const;
};

test.cpp

#include <test.h>

inline void print()
{
    // implementation
}

inline void A::print() const
{
    // implementation
}

main.cpp

#include <test.h>

int main(int argc, char** argv)
{
    print(); // undefined reference to `print()'
    A a;
    a.print(); // undefined reference to `A::print() const'

    return 0;
}

Я прочитал некоторые ответы здесь, но до сих пор не уверен, как это работает.


person arauter    schedule 03.06.2018    source источник
comment
Возможно, потому что можно встраивать функции в файлы .cpp. Если вы удалите inline из функций, они будут работать и возможно даже встроенный.   -  person Bo Persson    schedule 03.06.2018


Ответы (3)


Ключевое слово inline действительно сбивает с толку, хотя для этого варианта использования оно все равно понятно, если вы знаете его значение.

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

В main.o вы вызываете эту функцию. Поэтому он пытается разрешить указатель на функцию, который не был создан, что вызывает эту ошибку компоновщика.

Найти такие случаи можно, например, с помощью предупреждения компилятора clang: -Wundefined-inline

ИЗМЕНИТЬ

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

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

person JVApen    schedule 03.06.2018
comment
Таким образом, никогда не будет указателя функции на функцию, когда эта функция встроена, независимо от того, скопировано ее содержимое или нет? - person arauter; 03.06.2018
comment
Может быть, это зависит от вашего компилятора. Хотя на это полагаться нельзя. Однако, если вы возьмете адрес, в игру вступят некоторые дополнительные уродства, позвольте мне добавить это. - person JVApen; 03.06.2018
comment
Ох, ладно. Но в этом случае компоновщик всегда будет жаловаться, даже если указатель функции может существовать? - person arauter; 03.06.2018

В. Почему невозможно встроить определения функций в файл .cpp?

Вы можете встраивать функции в файл cpp.

Чего вы не можете сделать, так это получить доступ к этим inline функциям из другого cpp файла.

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

person Galik    schedule 03.06.2018

С сайта cppreference.com:

Определение встроенной функции или переменной (начиная с C++17) должно присутствовать в единице перевода, где к ней осуществляется доступ (не обязательно перед точкой доступа).

Ваши функции определены в test.cpp, но вы получаете к ним доступ из main.cpp.

person Mikhail Vasilyev    schedule 03.06.2018