rausted
rausted

Reputation: 959

Natural arithmetic C++ always returns 1

I'm trying to implement Natural numbers with C++, here's the code I have so far (O() is the 0 (zero) number and S(Nat) is the successor function).

// Peano arithmetic C++
// Null element
struct O{
    explicit operator const unsigned int() const { return 0; }
};

// Successor function    
struct S {
    unsigned int val; 
    explicit operator const unsigned int() const {
        // Boundary check
        std::cout << "Incremented once" << std::endl;
        if (this->val < UINT_MAX) {
            return this->val + 1;
        }
        // Don't wrap around, hit the ceiling and stay there
        return this->val;
    }
    S(const unsigned int a) {
        this->val = a;
    }
    // Constructor
    S(const O& zero) {
        this->val = 0;
    }
    S(const S& s) {
        this->val = static_cast<const unsigned int>(s);
    }
};

// Nat
using Nat = std::variant<O, S>;

int main() {
    std::cout << static_cast<const unsigned int>(S(O())) << std::endl;
    std::cout << static_cast<const unsigned int>(S(S(O()))) << std::endl;
    return 0;
}

What I expected was the static_cast to unsigned to give me 1, 2. What I get is actually 1, 1!

Upvotes: 1

Views: 148

Answers (1)

interjay
interjay

Reputation: 110145

S(const S& s) is a copy constructor, and the compiler is allowed to elide calls to the copy constructor in certain cases. This is an optional optimization in C++14 and below, and required in C++17. You can verify that this happens here by putting a print statement inside this constructor, which won't print anything.

In this case, it will make the expression S(S(O())) equivalent to S(O()).

Therefore, this way of doing things won't work here. You can make S a function instead, which can return either an integer (making it trivial), or some object if you prefer to keep things similar to your code here.

Upvotes: 2

Related Questions