Почему constexpr решает дублированное определение? - PullRequest
1 голос
/ 28 февраля 2020

У меня есть файл заголовка, в котором строка определяется как stati c global.

namespace space {
#define NAME(P) static std::string const s_##P = #P
        NAME(foo); NAME(bar); //... other values
#undef  NAME
}

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

enum class letter { alpha, beta };

template<letter> std::string const & mapping();
#define MAPPING(P1,P2) template<> std::string const & mapping<letter::P1>() { return space::s_##P2; }
        MAPPING(alpha,foo)
        MAPPING(beta,bar)
#undef  MAPPING

Приведенный выше код не связывается, когда заголовок включен в несколько единиц перевода, поскольку определения специализаций не совпадают - из-за глобального переопределения для единицы перевода (я полагаю) .

Обертывание функций отображения в анонимном пространстве имен или добавление ключевого слова static решает проблему компоновки, но затем компилятор жалуется, что функции defined but not used [-Wunused-function].

template<letter> static std::string const & mapping();

Но, определяя специализации как constexpr, больше нет ссылок или предупреждений.

template<letter> std::string const & mapping();
#define MAPPING(P1,P2) template<> constexpr std::string const & mapping<letter::P1>() { return space::s_##P2; }

Я понимаю, почему не-1019 * версия терпит неудачу во время соединения и почему версия static работает и вызывает предупреждения , Но я не понимаю, почему спецификатор constexpr решает обе проблемы.

Не могли бы вы дать объяснение и, что еще лучше, рациональный стандарт?

Ответы [ 2 ]

3 голосов
/ 28 февраля 2020

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

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

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

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

1 голос
/ 28 февраля 2020

функции, объявленные с помощью спецификатора constexpr, являются встроенными функциями.

Из стандарта C ++ 20 (9.2.5 Спецификаторы constexpr и consteval)

1 Должен применяться спецификатор constexpr только к определению переменной или шаблона переменной или объявлению функции или шаблона функции. Спецификатор consteval должен применяться только к объявлению функции или шаблона функции. Элемент данных функции или состояния c, объявленный с помощью спецификатора constexpr или consteval, неявно является встроенной функцией или переменной (

...