5

I would like to do math operations with IP addresses from boost::asio. Specifically I need to increment and/or add a given integer on an existing address to ease IP list generation in a software that I'm writing.

As today I'm using custom classes to handle IP addresses and networks, but I would like to move to boost::asio so I can rely on them to properly check/validade addresses and network attributes.

I have this working code as example (except for the operator+ part):

using boost::asio::ip::make_address_v4;
using boost::asio::ip::address_v4;

auto add(const address_v4& address, std::size_t value = 1) {
    return make_address_v4(address.to_uint() + value);
}

// This is definitely wrong
auto operator+(std::size_t value, const address_v4& address) {
    return add(address, value);
}

int main() {
    auto ip1 = make_address_v4("192.168.1.1");
    fmt::print("IP address: {}\n", ip1.to_string());

    auto ip2 = make_address_v4(ip1.to_uint() + 1);
    fmt::print("IP address: {}\n", ip2.to_string());

    // Add function
    fmt::print("Added IP: {}\n", add(ip2, 8).to_string());
    fmt::print("Added IP: {}\n", add(ip2).to_string());

    // operator+
    fmt::print("Added IP: {}\n", (ip2 + 4).to_string());

    return 0;
}

add function works as expected, but I don't know how to overload it so I can do things like: ip++ or ip + 4.

Also is there a better way to do math with boost::asio::ip::address_v4? I'm always getting values as uint and doing the math there.

Another solution that I was thinking was to inherit boost::asio::ip::address_v4 and create the custom operators, but I don't know if this would work and if it works, this seems overkill, or even worse, I don't know if this is a good practice, it looks like it doesn't.

Thank you.

  • 1
    you can simply swap the parameter's order for `operator+` function to make another `operator+` overload then it'll work. `auto operator+(const address_v4& address, std::size_t value) { return add(address, value); }` – M. Galib Uludag May 27 '22 at 20:07

1 Answers1

1

To technically work you need the overload:

// This is morally wrong
auto operator+(const address_v4& address, std::size_t value) {
    return add(address, value);
}

That's because the left-hand operand is address_v4, not size_t.

Live demo

However, please don't do this. See e.g. What are the basic rules and idioms for operator overloading?. There is no clear and undisputed meaning of the operation here. There is much room for surprises. Depending on subnetting, incrementing an address can make a regular address into a broadcast address, or even cross over into different subnets.

E.g. "10.10.9.254" + 0x01010101 == 11.11.10.255 makes little sense, and "255.255.255.255" + 0x01010101 == "1.1.1.0" even less.

What you probably want here is a subnet-aware enumerator/iterator interface, perhaps even with random sampling if you need non-sequential traversal. If you abstract this away as if address_v4 is "just an arithmetic type" you're lying about your domain information.

sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thanks @sehe, but I need to increment it anyway. operator++ would be sufficient, I do understand your reasoning and I was thinking how I could make it safe, perhaps throwing when the network is out of it's boundaries for example. A overflow check is also a good idea. The idea to overload + is to make the code more easy to read, since I'll be doing +1 in a for loop to generate a list of addresses. – Vinícius Ferrão May 27 '22 at 21:53
  • Tell me, what makes it so that `++address` is okay, but `increment(address)` isn't? The "I'll be doing +1 in a for loop to generate a list of addresses" was **exactly** what made me say `What you probably want here is a subnet-aware enumerator/iterator interface`. – sehe May 27 '22 at 21:55
  • increment(address) is also okay. So to be clear you would recommend using a function instead and forget about overloading operator+ (and operator++). – Vinícius Ferrão May 27 '22 at 21:59
  • 1