2014-12-07 1 views
21

У меня есть класс Dimension, который я определил (как и все мои классы) в файле Dimension.h:Можно ли объявить класс constexpr в заголовке и определить его в отдельном файле .cpp?

class Dimension 
{ 
public: 

    constexpr Dimension() noexcept; 

    constexpr Dimension(int w, int h) noexcept; 

    int width; 
    int height; 

}; 

Я думал, что я мог бы, как и во всех моих классах, поместить определение в отдельном Dimension.cpp :

#include "Dimension.h" 

constexpr Dimension::Dimension() noexcept : width(0), height(0) {} 

constexpr Dimension::Dimension(int w, int h) noexcept : width(w), height(h) {} 

но когда я пытаюсь использовать класс, компилятор говорит мне:

предупреждение: встроенная функция «constexpr Dimension::Dimension()» используется, но не определен

и в то время как связь:

неопределенная ссылка на 'pong::graphics::Dimension::Dimension()'

(то же самое с другой конструктор)

Если я определить класс в заголовке следующим образом:

class Dimension 
{ 
public: 

    constexpr Dimension() noexcept : width(0), height(0) {} 

    constexpr Dimension(int w, int h) noexcept : width(w), height(h) {} 

    int width; 
    int height; 

}; 

и опустить файл .cpp, все работает нормально.

Я использую GCC 4.9.2. Почему отдельное определение не работает?

+7

Весь смысл функции 'constexpr' - это позволить оценить функцию во время компиляции.Что было бы довольно сложно снять, если компилятор не может видеть тело указанной функции. –

+2

_ «Почему отдельное определение не работает?» _ - Потому что язык этого не позволяет. Примите это, сделайте это правильно, двигайтесь дальше. –

+0

Я уже подозревал, что, но я не совсем уверен, могу ли я объяснить (возможно, с рекомендациями), почему это происходит именно так. Я ничего не нашел об этом во время поиска в Google, поэтому я решил, что новый вопрос для этого был уместным. –

ответ

27

Если в заголовке не определена функция constexpr, компилятор не может определить определение функций constexpr при компиляции всех других исходных файлов.

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

Благодаря @IgorTandetnik:
[dcl.constexpr] §7.1.5/2

constexpr функции и constexpr Конструкторы неявно рядный.

[basic.def.odr] §3.2/4

Инлайн функция должна быть определена в каждом единице перевода, в котором он ODR использовать.

5

Что вы спрашиваете, может быть достигнут, с существенным ограничением: функция constexpr затем может быть вызвана только внутри блок перевода (то есть исходный файл), где она определена. Это не подходит для примера, который вы дали, поскольку конструктор должен быть частью открытого интерфейса класса. Однако это может быть очень полезно в других случаях, например. определить частные методы как constexpr, а затем использовать их возвращаемые значения в выражениях, которые должны быть известны во время компиляции, например. экземпляры шаблонов, метки операторов switch и т. д.

Смежные вопросы