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

Inline vs constexpr для статического констеллера?

В следующем фрагменте кода, какая функция позволит наилучшую оптимизацию для внешнего использования и почему? Разрешена ли версия "Версия 4" на С++ 2011?

template<unsigned int TDIM> class MyClass 
{
    public:
        static inline unsigned int size()           {return _size;} // Version 1
        static inline const unsigned int size()     {return _size;} // Version 2
        static constexpr unsigned int size()        {return _size;} // Version 3
        static inline constexpr unsigned int size() {return _size;} // Version 4
    protected:
        static const unsigned int _size = TDIM*3;
};

Большое спасибо.

4b9b3361

Ответ 1

Я считаю, что код в <random> служит хорошим примером, но также не нужно соблюдать рабски. В <random> вы видите оба этих стиля:

template<unsigned int TDIM> class MyClass 
{
    public:
        static constexpr unsigned int size() {return _size;}  // 1
        static constexpr unsigned int dim = TDIM;             // 2
    private:
        static const unsigned int _size = TDIM*3;
};

Выбор между 1 и 2 в значительной степени стилистичен. Они оба решаются во время компиляции, когда они используются таким образом, чтобы требовать результата компиляции. Вы хотите, чтобы ваши клиенты набрали () или нет? Есть ли общий код, который должен использовать один стиль или другой? Удовлетворение требований общего кода является ключевым здесь.

Использование ключевого слова inline здесь не влияет. Я считаю это слишком многословным, но это не наносит вреда и не имеет никакого влияния, если вы его используете.

Добавление const к типу возврата не окажет никакого влияния. Я считаю это слишком многословным, но это не наносит вреда и не имеет никакого влияния, если вы его используете.

Если вы используете стиль функции, но не используете constexpr:

    static unsigned int size() {return _size;}

то эту функцию нельзя вызывать во время компиляции и, следовательно, не может использоваться в контексте, который ожидает константу времени компиляции. Это может не нанести вреда вашему приложению или вашим клиентам, если они не нуждаются в такой функциональности. Но imho, если у вас есть constexpr в панели инструментов, это идеальное место для его использования. Если вы делаете будущий клиент, можете делать такие вещи:

template <unsigned N> struct B {};
constexpr auto myclass = MyClass<3>();
// ...
// lots of code here
// ...
B<myclass.size()> b;

Эти два эквивалента:

        static constexpr unsigned int dim = TDIM;        // 2
        static const unsigned int dim = TDIM;            // 3

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

class A
{
    unsigned _i;
public:
    constexpr A(unsigned i) : _i(i) {}
};

template<unsigned int TDIM> class MyClass 
{
    public:
        static constexpr unsigned int size() {return _size;}
        static constexpr unsigned int dim = TDIM;
        static constexpr A a = A(dim);
    private:
        static const unsigned int _size = TDIM*3;
};

Все здесь, включая меня, все еще учатся использовать constexpr. Итак, +1 на вопрос.

Ответ 2

static const integer values ​​рассматриваются как константы, а не как переменные компилятором. В зависимости от константы они могут вообще не иметь никакой памяти. Во всех ваших примерах функция вернет постоянное значение и почти всегда будет входить в нее (как уже упоминалось выше, ключевое слово inline в этом примере не обязательно, поскольку все объявления уже встроены).

Приведенный выше код не отличается от перспективы компилятора:

static unsigned int size() { return 42; }

Также ключевое слово 'const' в версии 2 не требуется. Я считаю, что это имеет смысл, если вы вернете указатель или ссылку.