Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are static constinit member variables identical to non-type template parameters?

I have a class template for an N-dimensional array:

template<typename T, std::size_t... Shape>
class ndarray { ... };

One consequence of this template design is that there is an additional 'implicit' template parameter if you will: std::size_t Size, the product of all arguments in Shape. I have been using a C++17 fold expression ((1 * ... * Shape)) where I would typically use Size if it weren't dependent on Shape, but I'm wondering if adding the following 'alias' would result in any subtle differences in the compiled assembly:

template<typename T, std::size_t... Shape>
class ndarray {
    static constinit std::size_t Size = (1 * ... * Shape);
    ...
};

Interestingly, the ISO C++20 standard doesn't state whether or not constinit implies inline as it does for constexpr and consteval. I think the semantics of constinit (especially in relation to constexpr variables) only really makes sense if the variable were also inline, but its omission from the standard makes me wary of this conclusion.

like image 851
QuaternionsRock Avatar asked Dec 14 '22 06:12

QuaternionsRock


2 Answers

constinit has exactly and only one semantic: the expression used to initialize the variable must be a constant expression.

That's it. That's all it does: it causes a compile error if the initializing expression isn't a valid constant expression. In every other way, such a variable is identical to not having constinit there. Indeed, the early versions of the proposal had constinit as an attribute rather than a keyword, since it didn't really do anything. It only gave a compile error for invalid initialization of the variable.

For this case, there is no reason not to make the variable constexpr. You clearly don't intend to change the variable, so there's no point in making the variable modifiable.

like image 148
Nicol Bolas Avatar answered Dec 15 '22 19:12

Nicol Bolas


No, these are not at all the same because constinit doesn't make the variable const. As such, the initialization of Size isn't even valid. Writing constinit const is mostly equivalent to writing constexpr, which is semantically equivalent to the constant fold-expression. There's no guarantee that any compiler does treat them identically, but in most constant-expression cases there isn't much room for variation.

constinit also doesn't imply inline: it isn't that the standard "doesn't state whether", it's just that there's nothing to say. Since there's no point in putting constinit and constexpr on the same variable, it's not clear what semantics you expect in that area.

like image 20
Davis Herring Avatar answered Dec 15 '22 20:12

Davis Herring