#constexpr my class

35 messages · Page 1 of 1 (latest)

viscid sable
#

So I have a basic class like this:

class SpriteBounds {
private:
    Sint16 _x, _y;
    Uint16 _w, _h;

    constexpr SpriteBounds(Sint16 x, Sint16 y, Uint16 w, Uint16 h) : _x(x), _y(y), _w(w), _h(h) { }

public:
    SpriteBounds(const BattleItem& battleItem);
    SpriteBounds(const RuleItem& ruleItem);

    constexpr SpriteBounds RelativeToInventory(const RuleInventory &inventory);
    constexpr SpriteBounds RelativeToSlot(const RuleSlot &slot);
    constexpr SpriteBounds Centered(const SDL_Rect& bounds);
    constexpr SpriteBounds Offset(const int x, const int y);
    constexpr SpriteBounds OffsetX(const int x) { return { _x + x, _y, _w, _h, }; }
    constexpr SpriteBounds OffsetY(const int y) { return { _x, _y + y, _w, _h, }; }
}```
All the member functions just do basic translations and then return a new instance of the class via the private ctor. Now while I don't expect this class can be fully inlined (because it has to be constructed from my dynamic items) my hope is that by making it constexpr the compiler can be smart enough and inline all the translations? 

That is when called like this:
```C++
const auto bounds = SpriteBounds(battleItem).RelativeToInventory(inventory).RelativeToSlot(slot).OffsetX(15);

The compiler can be smart enough that instead of creating a bunch of objects it can just perform all the translations "inline" as it were.

Is this a foolish hope? Does it even matter for so small a struct? Should I just mutate instead? Is there a better way?

magic tuskBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

signal bloom
#

Probably shouldn't matter that much, but I'll let the experts handle this

odd bison
#

but constexpr were it makes sense

#

for example it doesnt make sense when the functions itself calls other functions which arent constexpr

#

and dont put constexpr/inline with the hopes that the compiler will inline it

inner atlas
#

The compiler is not required to elide the temporaries here, no

odd bison
#

nowadays you shouldnt put inline with the hopes the compiler might optimize something, compiler is free to inline it or not and these hints are all likely just ignored

inner atlas
#

Yeah, inline is a really poorly named keyword

#

It describes ODR stuff

#

If you want to make sure a new object isn't recated, return references in your chain instead of new objects

viscid sable
#

well I wasn't planning on putting inline 😛

inner atlas
#

I'd probably mutate it, or use a builder

viscid sable
#

but that means mutating. Which... I don't know. It's not a big deal, but my preference is to not mutate when I don't have to.

inner atlas
#

I get that, but you're calling non-const member methods. I expect those to mutate

odd bison
#

you shouldnt create new objects when you dont have to, imo

viscid sable
#

oh, I just didn't add const, I meant to.

#

I guess I was just hoping I could have my pie and eat it to. The compiler being smart enough to see what I was doing and just... do that.

inner atlas
#

But yeah, most sane compilers will get rid of those temporaries for trivial types, but I wouldn't rely on it

viscid sable
#

I suppose mutating and returning a reference does enforce the behavior I want, though it's also questionable if thats actually advantageous for a struct so small.

inner atlas
#

Either use a builder to create your objects, or just allow chaining (to the same object)

#

C++20's designated init is also an option

odd bison
#

out of curiosity how are you defining Uint16

viscid sable
#

mmm, it's from SDL.h, sec.

odd bison
#

ah then nvm

viscid sable
#

typedef uint16_t Uint16;

odd bison
#

nice saved two characters :p

viscid sable
#

if I return a reference, is there any point in still using constexpr ? I mean... I guess it could still figure it out.

odd bison
#

you can use it in a constant expression?

viscid sable
#

well if the object it refers to is constexpr, then?

inner atlas
#

what you have there is not constexpr legal

#
class SpriteBounds {
private:
    Sint16 _x{}, _y{};
    Uint16 _w{}, _h{};

    constexpr SpriteBounds(Sint16 x, Sint16 y, Uint16 w, Uint16 h) : _x(x), _y(y), _w(w), _h(h) { }

public:
    constexpr SpriteBounds(const BattleItem& battleItem) {};
    constexpr SpriteBounds(const RuleItem& ruleItem) {};

    constexpr SpriteBounds& RelativeToInventory(const RuleInventory &inventory) { return *this; }
    constexpr SpriteBounds& RelativeToSlot(const RuleSlot &slot) { return *this; }
    constexpr SpriteBounds& Centered(const SDL_Rect& bounds) { return *this; }
    constexpr SpriteBounds& Offset(const int x, const int y) { return *this; }
    constexpr SpriteBounds& OffsetX(const int x) { return *this; }
    constexpr SpriteBounds& OffsetY(const int y) { return *this; }
};

you'd need something like that

magic tuskBOT
#

@viscid sable Has your question been resolved? If so, type !solved :)

viscid sable
#

hmm... it does seem in a trivial case it wipes it all away, but I need to figure out someway to generate a more realistic test case:
https://godbolt.org/z/bsbvYvYEb

#

okay... this looks like a better test I think?
https://godbolt.org/z/8xb3qbxnW