Подтвердить что ты не робот

Статический constexpr int vs старомодный enum: когда и почему?

Это, возможно, основной вопрос, но я не могу сразу увидеть ответ.

Рассмотрим следующий код:

template<bool b>
struct T {
    static constexpr int value = (b ? 42 : 0);
};

template<bool b>
struct U {
    enum { value = (b ? 42 : 0) };
};

int main() {
    static_assert(T<true>::value == 42, "!");
    static_assert(T<false>::value == 0, "!");
    static_assert(U<true>::value == 42, "!");
    static_assert(U<false>::value == 0, "!");
}

Я использую такие структуры, как T, но не раз я видел такие структуры, как U, используемые для той же цели (в основном определение признаков).

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

Мой вопрос довольно прост: есть ли какая-либо техническая причина, по которой одно решение лучше, чем другое?
Более того, есть ли случай, для которого один из них не является жизнеспособным решением?

4b9b3361

Ответ 1

Не будет заметной разницы для интегральных констант при использовании как это.

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

#include <iostream>

struct T {
    static constexpr int i = 42;
    enum : int {x = 42};
};

void check(const int& z) {
    std::cout << "Check: " << z << "\n";
}

int main() {
    // check(T::i); // Uncommenting this will lead to link error
    check(T::x);
}

Когда check(T::i) раскоментирован, программа не может быть связана:

/tmp/ccZoETx7.o: В функции ` main ': ccc.cpp: (.text+0x45): undefinedссылка на `T::i 'collect2: ошибка: ld возвращен 1 статус выхода

Однако true enum всегда работает.

Ответ 2

Я подозреваю, что это устаревший код.

enum { value = (b ? 42 : 0) };

является допустимым кодом в С++ 03, а также С++ 11.

static constexpr int value = (b ? 42 : 0);

действителен только в С++ 11.

Более того, есть ли случай, для которого один из них не является жизнеспособным решением?

Оба являются жизнеспособными решениями в С++ 11. Выбор того, какой из них использовать, зависит от команды. Это будет политическое решение.

Как ответ SergeyA указывает, что enum являются истинными константами. Вы не можете использовать ODR. Вы можете использовать ODR . В зависимости от того, какое из них желательно для вашего приложения, вы можете решить, следует ли использовать enum или constexpr s.

Ответ 3

В настоящее время принятый ответ SergeyA больше не относится к С++ 17 (Определения и ODR).

Каждое объявление является определением, за исключением следующего:

  • ...
  • (устарело) Объявление области пространства имен для статического члена данных, который был определен в классе с помощью спецификатора constexpr
struct S {
    static constexpr int x = 42; // implicitly inline, defines S::x
};
constexpr int S::x; // declares S::x, not a redefinition

Следовательно, начиная с С++ 17, я бы использовал определение static constexpr, которое более выразительно, чем enum.