Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inline vs constexpr for a static const getter?

In the following piece of code, what function will allow the best optimization for an external use and why ? Is the "Version 4" allowed in C++ 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;
};

Thank you very much.

like image 651
Vincent Avatar asked Aug 12 '12 00:08

Vincent


People also ask

Should constexpr be static?

A constexpr variable must have static storage at some point, it's baked in when the program is compiled.

Should I use constexpr or const?

const applies for variables, and prevents them from being modified in your code. constexpr tells the compiler that this expression results in a compile time constant value, so it can be used in places like array lengths, assigning to const variables, etc.

Why does constexpr need to be static?

A static constexpr variable has to be set at compilation, because its lifetime is the the whole program. Without the static keyword, the compiler isn't bound to set the value at compilation, and could decide to set it later.

Is constexpr faster?

Try it on your code baseNot only will your code be faster and smaller, it'll be safer. Code marked constexpr can't bitrot as easily.


1 Answers

I believe that the code in <random> sets a good example, but also need not be followed slavishly. In <random> you see both of these styles:

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;
};

The choice between 1 and 2 is largely stylistic. They are both resolved at compile time when used in a way that demands a compile-time result. Do you want your clients to type () or not? Is there generic code that will need to use one style or the other? Satisfying the requirements of generic code is key here.

Use of the inline keyword has no impact here. I consider it overly verbose, but it does no harm and has no impact if you use it.

Adding const to a return type will have no impact here. I consider it overly verbose, but it does no harm and has no impact if you use it.

If you use the function style, but do not use constexpr:

    static unsigned int size() {return _size;}

then this function can not be called at compile-time, and thus can not be used in a context which expects a compile-time constant. That may not cause any harm for your application or your clients if they don't need such functionality. But imho, if you've got constexpr in the toolbox, this is the perfect place to use it. If you do a future client can do stuff like this:

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

These two are equivalent:

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

but only because the involved type is integral. If the type is not integral, then you have to use constexpr and the type has to have a constexpr constructor:

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;
};

Everyone here, including myself, is still learning how to use constexpr. So +1 on the question.

like image 66
Howard Hinnant Avatar answered Oct 14 '22 11:10

Howard Hinnant