Проблема возникает из-за ряда ограничений:
- Семантика значений требует, чтобы для компиляции «вызова» вам нужно было знать параметры и размеры возвращаемых типов.
- эти знания должны быть доступны компилятору во время компиляции той же единицы трансляции, но ...
- знания, полученные из определений, доступны только во время компоновки, то есть это отдельный шаг, который происходит помимо компиляции.
Еще больше усложняет то, что грамматика C ++ меняет значение в зависимости от того, являются ли символы переменными или типами (так, без этого знания a<b>c
даже невозможно узнать, что это означает: выражение, включающее три переменные, или объявление переменной типа, заданного экземпляром шаблона ).
Определение функции может находиться в другом исходном файле, и компилятор - при компиляции первого - не имеет возможности получить к нему доступ и, следовательно, знать, какой ширины должно быть место в стеке для передачи параметров и возврата.
Ваш образец - в широком проекте - будет иметь код как
//test.h
double test();
__
//test.cpp
#include "test.h" //required to check decl & def consistence
double test()
{ /*...*/ }
__
//main.cpp
#include "test.h" // required to know about test() parameters and return
int main()
{
double z = test(); //how does "=" translate? we need to know what test returns
}
Этот «проект» будет скомпилирован с использованием независимых шагов:
g++ -c main.cpp //on a program developer machine
g++ -c test.cpp //on a library developer machine
g++ main.o test.o -o yourprogram //on a "package distributor" machine
Ни один из этих шагов не может собрать «глобальные знания» обо всех «глобальных символах» и их «переводе» одновременно. Вот почему нам нужны заголовки, чтобы транслировать объявления всем, кто должен их использовать.
(Обратите внимание, что у функций-членов нет этой проблемы, поскольку все они должны оставаться в одних и тех же скобках класса и, как следствие, могут соответствовать одной и той же единице перевода)
У таких языков, как Java или Python, этой проблемы нет, поскольку все модули (независимо от того, как они написаны и загружены) загружаются одним и тем же экземпляром языковой машины, который, будучи уникальным, может собирать все символы и связанные типы. .
такие языки, как D (которые похожи на C ++ в смысле «раздельной компиляции»), позволяют независимость порядка между объектами, находящимися в одном модуле, но требуют «импорта» модуля для вещей, поступающих из других модулей, и фактически выполняют два шага перевод, сначала собирая символы и типы, а затем выполняя переводы вызовов.
Вы можете увидеть другое описание этой проблемы здесь
person
Emilio Garavaglia
schedule
01.09.2016