Doc. no: N4044 Date: 2014-05-24 Revises: N3603 Reply-To: Christopher Kohlhoff <chris@kohlhoff.com>
Table of Contents
This proposal describes a three-class design for IP address classes:
ip::address
, for use in IP version independent
code.
ip::address_v4
.
ip::address_v6
.
This proposal describes only types necessary to support the manipulation of IP (Internet Protocol) addresses. Other networking facilities, such as sockets and name resolution, are outside the scope of this proposal.
The proposed interface is primarily intended for use by developers writing programs with a networking component, and in particular programs that utilise internet protocols such as TCP and UDP.
This proposal is based on the IP address classes in the Boost.Asio library. The proposed text was originally from N2175 "Networking Library Proposal for TR2 (Revision 1)" with small modifications to reflect enhancements made to Boost.Asio since 2007.
In this revision, the proposed text has been updated to reflect feedback and discussion from the Bristol 2013 meeting of SG4. A reference implementation of the proposal is available from GitHub.
This is a pure library proposal. It does not add any new language features, nor does it alter any existing standard library headers.
This library can be implemented using compilers that conform to the C++11 standard. An implementation of this library requires operating system-specific functions that lie outside the C++11 standard.
For more information on the motivating design decisions for the three-class design, please consult N3603.
In this section we list some of the additional proposed changes that were considered but rejected. The changes incorporated since N3603 are described at the end.
One suggestion was that the proposal should include overloads of hton
and ntoh
for the address types. The motivating use case was that address objects may
be used directly as part of standard-layout aggregates that are ultimately
intended for network transmission.
This change was rejected on the basis that the applying hton
to a class type (as opposed to a simple integer) may result in an object
that is in an invalid or nonsensical state. As a matter of style, the author
feels that the address types should be treated as abstractions without necessarily
forcing a particular internal implementation.
The addresses' to_bytes()
member functions can already be used to obtain a representation of the address
in network byte order. To further aid the motivating use case, the bytes_type
types have been changed to be
unique types.
Another suggestion was that the address types should specialise std::less<>
rather than provide operator<
and friends. This change was rejected since it would appear to render the
address types incompatible with other standard library types, such as std::tuple<>
, which apply operator<
to their elements.
It has been suggested in the SG4 discussion forum that the address classes include the ability to determine the predecessor or successor of an address. By this we mean that given an address 1.2.3.4, the predecessor address is 1.2.3.3 and the successor is 1.2.3.5.
The author feels that this feature is not a core responsibility of the address classes, but if it is desired it can instead be supported by a richer range-based interface. The following is a sketch of this approach:
class address_iterator_v4 { public: typedef std::ptrdiff_t difference_type; typedef address_v4 value_type; typedef const address_v4* pointer; typedef const address_v4& reference; typedef std::bidirectional_iterator_tag iterator_category; explicit address_iterator_v4(const address_v4& addr); const address_v4& operator*() const; const address_v4* operator->() const; address_iterator_v4& operator++(); address_iterator_v4 operator++(int); address_iterator_v4& operator--(); address_iterator_v4 operator--(int); friend bool operator==(const address_iterator_v4& a, const address_iterator_v4& b); friend bool operator!=(const address_iterator_v4& a, const address_iterator_v4& b); private: // ... }; class address_range_v4 { public: address_range_v4(); explicit address_range_v4(const address_v4& addr); explicit address_range_v4(const address_v4& addr, const address_v4& mask); address_v4 network() const; address_v4 netmask() const; address_v4 broadcast() const; typedef address_iterator_v4 iterator; iterator begin() const; iterator end() const; iterator find(const address_v4& addr) const; private: // ... };
This may be used as in the following example:
address_range_v4 range( make_address_v4("192.168.1.0"), make_address_v4("255.255.255.0")); for (auto a: range) std::cout << a << std::endl; std::cout << "---" << std::endl; std::for_each( range.find(make_address_v4("192.168.1.250")), range.end(), [](address_v4 a) { std::cout << a << std::endl; });
If SG4 determines that this feature is desirable, it may be added to this proposal or developed as a separate proposal. The author favours the latter.
See section 1.4 of N3783 Network Byte Order Conversion.
See section 1.4 of N3783 Network Byte Order Conversion.
Network library functions often provide two overloads, one that throws an
exception to report system errors, and another that sets an error_code
.
[Note: This supports two common use cases:
— Uses where system errors are truly exceptional and indicate a serious failure.
Throwing an exception is the most appropriate response. This is the preferred
default for most everyday programming.
— Uses where system errors
are routine and do not necessarily represent failure. Returning an error
code is the most appropriate response. This allows application specific error
handling, including simply ignoring the error.
—end
note]
Functions not having an argument of type
error_code&
report errors as follows, unless otherwise specified:
— When a call by the implementation to an operating system or other underlying
API results in an error that prevents the function from meeting its specifications,
an exception of type system_error
shall be thrown.
— Failure to allocate storage is reported by throwing an exception as described in the C++ standard (C++14 [res.on.exception.handling]).
— Destructors throw nothing.
Functions having an argument of type error_code&
report errors as follows, unless otherwise
specified:
— If a call by the implementation to an operating system or other underlying
API results in an error that prevents the function from meeting its specifications,
the error_code&
argument is set as appropriate for the specific error. Otherwise, clear()
is called on the error_code&
argument.
This clause describes components that C++ programs may use to manipulate IP addresses.
namespace std { namespace experimental { namespace net { // Internet protocol addresses: namespace ip { struct v4_mapped_t {}; constexpr v4_mapped_t v4_mapped; class address; class address_v4; class address_v6; class bad_address_cast; // address comparisons: bool operator==(const address&, const address&) noexcept; bool operator!=(const address&, const address&) noexcept; bool operator< (const address&, const address&) noexcept; bool operator> (const address&, const address&) noexcept; bool operator<=(const address&, const address&) noexcept; bool operator>=(const address&, const address&) noexcept; // address_v4 comparisons: bool operator==(const address_v4&, const address_v4&) noexcept; bool operator!=(const address_v4&, const address_v4&) noexcept; bool operator< (const address_v4&, const address_v4&) noexcept; bool operator> (const address_v4&, const address_v4&) noexcept; bool operator<=(const address_v4&, const address_v4&) noexcept; bool operator>=(const address_v4&, const address_v4&) noexcept; // address_v6 comparisons: bool operator==(const address_v6&, const address_v6&) noexcept; bool operator!=(const address_v6&, const address_v6&) noexcept; bool operator< (const address_v6&, const address_v6&) noexcept; bool operator> (const address_v6&, const address_v6&) noexcept; bool operator<=(const address_v6&, const address_v6&) noexcept; bool operator>=(const address_v6&, const address_v6&) noexcept; // address creation: address make_address(const char*); address make_address(const char*, error_code&) noexcept; address make_address(const string&); address make_address(const string&, error_code&) noexcept; // address_v4 creation: constexpr address_v4 make_address_v4(const address_v4::bytes_type&); constexpr address_v4 make_address_v4(unsigned long); constexpr address_v4 make_address_v4(v4_mapped_t, const address_v6&); address_v4 make_address_v4(const char*); address_v4 make_address_v4(const char*, error_code&) noexcept; address_v4 make_address_v4(const string&); address_v4 make_address_v4(const string&, error_code&) noexcept; // address_v6 creation: constexpr address_v6 make_address_v6(const address_v6::bytes_type&, unsigned long = 0); constexpr address_v6 make_address_v6(v4_mapped_t, const address_v4&) noexcept; address_v6 make_address_v6(const char*); address_v6 make_address_v6(const char*, error_code&) noexcept; address_v6 make_address_v6(const string&); address_v6 make_address_v6(const string&, error_code&) noexcept; // address I/O: template<class CharT, class Traits> basic_ostream<CharT, Traits>& operator<<( basic_ostream<CharT, Traits>&, const address&); // address_v4 I/O: template<class CharT, class Traits> basic_ostream<CharT, Traits>& operator<<( basic_ostream<CharT, Traits>&, const address_v4&); // address_v6 I/O: template<class CharT, class Traits> basic_ostream<CharT, Traits>& operator<<( basic_ostream<CharT, Traits>&, const address_v6&); // address conversions: template <class T> constexpr T address_cast(const address&) noexcept(see below); template <class T> constexpr T address_cast(const address_v4&) noexcept(see below); template <class T> constexpr T address_cast(const address_v6&) noexcept(see below); } // namespace ip } // namespace net // hash support template <class T> struct hash; template <> struct hash<net::ip::address>; template <> struct hash<net::ip::address_v4>; template <> struct hash<net::ip::address_v6>; inline namespace literals { inline namespace net_literals { // suffixes for address literals net::ip::address operator "" ip(const char*, size_t); net::ip::address_v4 operator "" ipv4(const char*, size_t); net::ip::address_v6 operator "" ipv6(const char*, size_t); } // namespace net_literals } // namespace literals } // namespace experimental } // namespace std
namespace std { namespace experimental { namespace net { namespace ip { class address { public: // constructors: constexpr address() noexcept; constexpr address(const address& a) noexcept; template <class T> constexpr address(const T& t) noexcept(see below); template <class... T> explicit constexpr address(T&&... t); // assignment: address& operator=(const address& a) noexcept; // members: constexpr bool is_unspecified() const noexcept; constexpr bool is_loopback() const noexcept; constexpr bool is_multicast() const noexcept; constexpr bool is_v4() const noexcept; constexpr bool is_v6() const noexcept; string to_string() const; string to_string(error_code& ec) const; }; // address comparisons: bool operator==(const address& a, const address& b) noexcept; bool operator!=(const address& a, const address& b) noexcept; bool operator< (const address& a, const address& b) noexcept; bool operator> (const address& a, const address& b) noexcept; bool operator<=(const address& a, const address& b) noexcept; bool operator>=(const address& a, const address& b) noexcept; // address creation: address make_address(const char* str); address make_address(const char* str, error_code& ec) noexcept; address make_address(const string& str); address make_address(const string& str, error_code& ec) noexcept; // address I/O: template<class CharT, class Traits> basic_ostream<CharT, Traits>& operator<<( basic_ostream<CharT, Traits>& os, const address& addr); } // namespace ip } // namespace net } // namespace experimental } // namespace std
constexpr address() noexcept;
Effects: Constructs an object of class
address
.
Postconditions: The postconditions of this function are indicated in the table below.
constexpr address(const address& a) noexcept;
Effects: Constructs an object of class
address
.
Postconditions:
*this == a
template <class T> constexpr address(const T& t) noexcept(see below);
Remarks: This constructor shall not participate in overload resolution unless
is_same<T, address>::value
isfalse
, and the expressionaddress_cast<address>(t)
is valid and yields an rvalue of typeaddress
. The expression insidenoexcept
shall be equivalent tonoexcept(address_cast<address>(t))
.
Effects: Constructs an object of type
address
with the result of the expressionaddress_cast<address>(t)
.
Throws: Nothing unless the expression
address_cast<address>(t)
throws an exception.
template <class... T> explicit constexpr address(T&&... t);
Remarks: This constructor shall not participate in overload resolution unless the expression
make_address(forward<T>(t).
.
.)
is valid and yields an rvalue of typeaddress
.
Effects: Constructs an object of type
address
with the result of the expressionmake_address(forward<T>(t).
.
.)
.
address& operator=(const address& a) noexcept;
Postconditions:
*this == a
Returns:
*this
constexpr bool is_unspecified() const noexcept;
Returns: If
is_v4() == true
, returnsaddress_cast<address_v4>(*this).is_unspecified()
. Ifis_v6() == true
, returnsaddress_cast<address_v6>(*this).is_unspecified()
. Otherwise returnsfalse
.
constexpr bool is_loopback() const noexcept;
Returns: If
is_v4() == true
, returnsaddress_cast<address_v4>(*this).is_loopback()
. Ifis_v6() == true
, returnsaddress_cast<address_v6>(*this).is_loopback()
. Otherwise returnsfalse
.
constexpr bool is_multicast() const noexcept;
Returns: If
is_v4() == true
, returnsaddress_cast<address_v4>(*this).is_multicast()
. Ifis_v6() == true
, returnsaddress_cast<address_v6>(*this).is_multicast()
. Otherwise returnsfalse
.
constexpr bool is_v4() const noexcept;
Returns:
true
if the object contains an IP version 4 address.
constexpr bool is_v6() const noexcept;
Returns:
true
if the object contains an IP version 6 address.
string to_string() const; string to_string(error_code& ec) const;
Returns: If
is_v4() == true
, returnsaddress_cast<address_v4>(*this).to_string(ec)
. Ifis_v6() == true
, returnsaddress_cast<address_v6>(*this).to_string(ec)
. Otherwise throwsbad_address_cast
.
bool operator==(const address& a, const address& b) noexcept;
Returns:
a_v4 == b_v4 && a_v6 == b_v6
, where:
—a_v4
is the value ofa.is_v4() ? address_cast<address_v4>(a) : address_v4()
;
—b_v4
isb.is_v4() ? address_cast<address_v4>(b) : address_v4()
;
—a_v6
isa.is_v6() ? address_cast<address_v6>(a) : address_v6()
; and
—b_v6
isb.is_v6() ? address_cast<address_v6>(b) : address_v6()
.
bool operator!=(const address& a, const address& b) noexcept;
Returns:
!(a == b)
.
bool operator< (const address& a, const address& b) noexcept;
Returns:
a_v6 < b_v6 || a_v6 == b_v6 && a_v4 < b_v4
, where:
—a_v4
is the value ofa.is_v4() ? address_cast<address_v4>(a) : address_v4()
;
—b_v4
isb.is_v4() ? address_cast<address_v4>(b) : address_v4()
;
—a_v6
isa.is_v6() ? address_cast<address_v6>(a) : address_v6()
; and
—b_v6
isb.is_v6() ? address_cast<address_v6>(b) : address_v6()
.
bool operator> (const address& a, const address& b) noexcept;
Returns:
b < a
.
bool operator<=(const address& a, const address& b) noexcept;
Returns:
!(b < a)
.
bool operator>=(const address& a, const address& b) noexcept;
Returns:
!(a < b)
.
address make_address(const char* str); address make_address(const char* str, error_code& ec) noexcept; address make_address(const string& str); address make_address(const string& str, error_code& ec) noexcept;
Effects: Converts a string representation of an address into an object of class
address
, as if by calling:address a; address_v6 v6a = make_address_v6(str, ec); if (!ec) a = v6a; else { address_v4 v4a = make_address_v4(str, ec); if (!ec) a = v4a; }
Returns:
a
.
template<class CharT, class Traits> basic_ostream<CharT, Traits>& operator<<( basic_ostream<CharT, Traits>& os, const address& addr);
Effects: Outputs the string representation of the address to the stream, as if it were implemented as follows:
error_code ec; string s = addr.to_string(ec); if (ec) { if (os.exceptions() & ios_base::failbit) throw system_error(ec); else os.setstate(ios_base::failbit); } else for (string::iterator i = s.begin(); i != s.end(); ++i) os << os.widen(*i);
Returns:
os
.
namespace std { namespace experimental { namespace net { namespace ip { class address_v4 { public: // types: struct bytes_type; // constructors: constexpr address_v4() noexcept; constexpr address_v4(const address_v4& a) noexcept; constexpr address_v4(const bytes_type& bytes); template <class... T> explicit constexpr address(T&&... t); // assignment: address_v4& operator=(const address_v4& a) noexcept; // members: constexpr bool is_unspecified() const noexcept; constexpr bool is_loopback() const noexcept; constexpr bool is_class_a() const noexcept; constexpr bool is_class_b() const noexcept; constexpr bool is_class_c() const noexcept; constexpr bool is_multicast() const noexcept; constexpr bytes_type to_bytes() const noexcept; constexpr unsigned long to_ulong() const noexcept; string to_string() const; string to_string(error_code& ec) const; // static members: static constexpr address_v4 any() noexcept; static constexpr address_v4 loopback() noexcept; static constexpr address_v4 broadcast() noexcept; static constexpr address_v4 broadcast(const address_v4& addr, const address_v4& mask) noexcept; }; // address_v4 comparisons: bool operator==(const address_v4& a, const address_v4& b) noexcept; bool operator!=(const address_v4& a, const address_v4& b) noexcept; bool operator< (const address_v4& a, const address_v4& b) noexcept; bool operator> (const address_v4& a, const address_v4& b) noexcept; bool operator<=(const address_v4& a, const address_v4& b) noexcept; bool operator>=(const address_v4& a, const address_v4& b) noexcept; // address_v4 creation: constexpr address_v4 make_address_v4(const address_v4::bytes_type& bytes); constexpr address_v4 make_address_v4(unsigned long val); constexpr address_v4 make_address_v4(v4_mapped_t, const address_v6& a); address_v4 make_address_v4(const char* str); address_v4 make_address_v4(const char* str, error_code& ec) noexcept; address_v4 make_address_v4(const string& str); address_v4 make_address_v4(const string& str, error_code& ec) noexcept; // address_v4 I/O: template<class CharT, class Traits> basic_ostream<CharT, Traits>& operator<<( basic_ostream<CharT, Traits>& os, const address_v4& addr); } // namespace ip } // namespace net } // namespace experimental } // namespace std
namespace std { namespace experimental { namespace net { namespace ip { struct address_v4::bytes_type : array<unsigned char, 4> { template <class... T> explicit constexpr bytes_type(T... t) : array<unsigned char, 4>{{static_cast<unsigned char>(t)...}} {} }; } // namespace ip } // namespace net } // namespace experimental } // namespace std
The ip::address_v4::bytes_type
type is a standard-layout
struct that provides a byte-level representation of an IPv4 address in
network byte order.
constexpr address_v4() noexcept;
Effects: Constructs an object of class
address_v4
.
Postconditions: The postconditions of this function are indicated in the table below.
constexpr address_v4(const address_v4& a) noexcept;
Effects: Constructs an object of class
address_v4
.
Postconditions:
*this == a
constexpr address_v4(const bytes_type& bytes);
Requires: Each element of
bytes
is in the range[0, 0xFF]
.
Throws:
out_of_range
if any element ofbytes
is not in the range[0, 0xFF]
. [Note: For implementations whereUCHAR_MAX == 0xFF
, no out-of-range detection is needed. —end note]
Postconditions:
to_bytes() == bytes
andto_ulong() == (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]
.
template <class... T> explicit constexpr address_v4(T&&... t);
Remarks: This constructor shall not participate in overload resolution unless the expression
make_address_v4(forward<T>(t).
.
.)
is valid and yields an rvalue of typeaddress_v4
.
Effects: Constructs an object of type
address_v4
with the result of the expressionmake_address_v4(forward<T>(t).
.
.)
.
address_v4& operator=(const address_v4& a) noexcept;
Postconditions:
*this == a
Returns:
*this
constexpr bool is_unspecified() const noexcept;
Returns:
to_ulong() == 0
.
constexpr bool is_loopback() const noexcept;
Returns:
(to_ulong() & 0xFF000000) == 0x7F000000
.
constexpr bool is_class_a() const noexcept;
Returns:
(to_ulong() & 0x80000000) == 0
.
constexpr bool is_class_b() const noexcept;
Returns:
(to_ulong() & 0xC0000000) == 0x80000000
.
constexpr bool is_class_c() const noexcept;
Returns:
(to_ulong() & 0xE0000000) == 0xC0000000
.
constexpr bool is_multicast() const noexcept;
Returns:
(to_ulong() & 0xF0000000) == 0xE0000000
.
constexpr bytes_type to_bytes() const noexcept;
Returns: A representation of the address in network byte order.
constexpr unsigned long to_ulong() const noexcept;
Returns: A representation of the address in host byte order.
string to_string() const; string to_string(error_code& ec) const;
Effects: Converts an address into a string representation, as if by POSIX
inet_ntop()
when invoked with address familyAF_INET
.
Returns: If successful, the string representation of the address. Otherwise
string()
.
static constexpr address_v4 any() noexcept;
Returns:
address_v4()
.
static constexpr address_v4 loopback() noexcept;
Returns:
address_v4(0x7F000001)
.
static constexpr address_v4 broadcast() noexcept;
Returns:
address_v4(0xFFFFFFFF)
.
static constexpr address_v4 broadcast(const address_v4& addr, const address_v4& mask) noexcept;
Returns:
address_v4(addr.to_ulong() | ~mask.to_ulong())
.
bool operator==(const address_v4& a, const address_v4& b) noexcept;
Returns:
a.to_ulong() == b.to_ulong()
.
bool operator!=(const address_v4& a, const address_v4& b) noexcept;
Returns:
a.to_ulong() != b.to_ulong()
.
bool operator< (const address_v4& a, const address_v4& b) noexcept;
Returns:
a.to_ulong() < b.to_ulong()
.
bool operator> (const address_v4& a, const address_v4& b) noexcept;
Returns:
a.to_ulong() > b.to_ulong()
.
bool operator<=(const address_v4& a, const address_v4& b) noexcept;
Returns:
a.to_ulong() <= b.to_ulong()
.
bool operator>=(const address_v4& a, const address_v4& b) noexcept;
Returns:
a.to_ulong() >= b.to_ulong()
.
constexpr address_v4 make_address_v4(const address_v4::bytes_type& bytes);
Returns:
address_v4(bytes)
.
constexpr address_v4 make_address_v4(unsigned long val);
Requires:
val
is in the range[0, 0xFFFFFFFF]
.
Throws:
out_of_range
ifval
is not in the range[0, 0xFFFFFFFF]
. [Note: For implementations whereULONG_MAX == 0xFFFFFFFF
, no out-of-range detection is needed. —end note]
Returns: An object
a
of typeaddress_v4
wherea.to_ulong() == val
anda.to_bytes()
is{ (val >> 24) & 0xFF, (val >> 16) & 0xFF, (val >> 8) & 0xFF, val & 0xFF }
.
constexpr address_v4 make_address_v4(v4_mapped_t, const address_v6& a);
Requires:
a.is_v4_mapped()
.
Returns: An
address_v4
object corresponding to the IPv4-mapped IPv6 address, as if computed by the following method:bytes_type v6b = a.to_bytes(); address_v4::bytes_type v4b(v6b[12], v6b[13], v6b[14], v6b[15]); return address_v4(v4b);
Throws:
bad_address_cast
ifa.is_v4_mapped()
is false.
address_v4 make_address_v4(const char* str); address_v4 make_address_v4(const char* str, error_code& ec) noexcept; address_v4 make_address_v4(const string& str); address_v4 make_address_v4(const string& str, error_code& ec) noexcept;
Effects: Converts a string representation of an address into a corresponding
address_v4
value, as if by POSIXinet_pton()
when invoked with address familyAF_INET
.
Returns: If successful, an
address_v4
value corresponding to the stringstr
. Otherwiseaddress_v4()
.
template<class CharT, class Traits> basic_ostream<CharT, Traits>& operator<<( basic_ostream<CharT, Traits>& os, const address_v4& addr);
Effects: Outputs the string representation of the address to the stream, as if it were implemented as follows:
error_code ec; string s = addr.to_string(ec); if (ec) { if (os.exceptions() & ios_base::failbit) throw system_error(ec); else os.setstate(ios_base::failbit); } else for (string::iterator i = s.begin(); i != s.end(); ++i) os << os.widen(*i);
Returns:
os
.
namespace std { namespace experimental { namespace net { namespace ip { class address_v6 { public: // types: struct bytes_type; // constructors: constexpr address_v6() noexcept; constexpr address_v6(const address_v6& a) noexcept; constexpr address_v6(const bytes_type& bytes, unsigned long scope); template <class... T> explicit constexpr address(T&&... t); // assignment: address_v4& operator=(const address_v4& a) noexcept; // members: void scope_id(unsigned long id) noexcept; constexpr unsigned long scope_id() const noexcept; constexpr bool is_unspecified() const noexcept; constexpr bool is_loopback() const noexcept; constexpr bool is_multicast() const noexcept; constexpr bool is_link_local() const noexcept; constexpr bool is_site_local() const noexcept; constexpr bool is_v4_mapped() const noexcept; constexpr bool is_multicast_node_local() const noexcept; constexpr bool is_multicast_link_local() const noexcept; constexpr bool is_multicast_site_local() const noexcept; constexpr bool is_multicast_org_local() const noexcept; constexpr bool is_multicast_global() const noexcept; constexpr bytes_type to_bytes() const noexcept; string to_string() const; string to_string(error_code& ec) const; // static members: static constexpr address_v6 any() noexcept; static constexpr address_v6 loopback() noexcept; }; // address_v6 comparisons: bool operator==(const address_v6& a, const address_v6& b) noexcept; bool operator!=(const address_v6& a, const address_v6& b) noexcept; bool operator< (const address_v6& a, const address_v6& b) noexcept; bool operator> (const address_v6& a, const address_v6& b) noexcept; bool operator<=(const address_v6& a, const address_v6& b) noexcept; bool operator>=(const address_v6& a, const address_v6& b) noexcept; // address_v6 creation: constexpr address_v6 make_address_v6(const address_v6::bytes_type& bytes, unsigned long scope_id = 0); constexpr address_v6 make_address_v6(v4_mapped_t, const address_v4& a) noexcept; address_v6 make_address_v6(const char* str); address_v6 make_address_v6(const char* str, error_code& ec) noexcept; address_v6 make_address_v6(const string& str); address_v6 make_address_v6(const string& str, error_code& ec) noexcept; // address_v6 I/O: template<class CharT, class Traits> basic_ostream<CharT, Traits>& operator<<( basic_ostream<CharT, Traits>& os, const address_v6& addr); } // namespace ip } // namespace net } // namespace experimental } // namespace std
[Note: The implementations of the functions is_unspecified
, is_loopback
,
is_multicast
, is_link_local
, is_site_local
,
is_v4_mapped
, is_multicast_node_local
, is_multicast_link_local
, is_multicast_site_local
, is_multicast_org_local
and is_multicast_global
are determined by
[RFC4291]. —end note]
namespace std { namespace experimental { namespace net { namespace ip { struct address_v6::bytes_type : array<unsigned char, 16> { template <class... T> explicit constexpr bytes_type(T... t) : array<unsigned char, 16>{{static_cast<unsigned char>(t)...}} {} }; } // namespace ip } // namespace net } // namespace experimental } // namespace std
The ip::address_v6::bytes_type
type is a standard-layout
struct that provides a byte-level representation of an IPv6 address in
network byte order.
constexpr address_v6() noexcept;
Effects: Constructs an object of class
address_v6
.
Postconditions: The postconditions of this function are indicated in the table below.
constexpr address_v6(const address_v6& a) noexcept;
Effects: Constructs an object of class
address_v6
.
Postconditions:
*this == a
constexpr address_v6(const bytes_type& bytes, unsigned long scope);
Requires: Each element of
bytes
is in the range[0, 0xFF]
.
Throws:
out_of_range
if any element ofbytes
is not in the range[0, 0xFF]
. [Note: For implementations whereUCHAR_MAX == 0xFF
, no out-of-range detection is needed. —end note]
Postconditions:
to_bytes() == bytes
andscope_id() == scope
.
template <class... T> explicit constexpr address_v6(T&&... t);
Remarks: This constructor shall not participate in overload resolution unless the expression
make_address_v6(forward<T>(t).
.
.)
is valid and yields an rvalue of typeaddress_v6
.
Effects: Constructs an object of type
address_v6
with the result of the expressionmake_address_v6(forward<T>(t).
.
.)
.
address_v6& operator=(const address_v6& a) noexcept;
Postconditions:
*this == a
Returns:
*this
void scope_id(unsigned long id) noexcept;
Postconditions:
scope_id() == id
.
constexpr unsigned long scope_id() const noexcept;
Returns: The scope identifier associated with the address.
constexpr bool is_unspecified() const noexcept;
Returns: A boolean indicating whether the
address_v6
object represents an unspecified address, as if computed by the following method:bytes_type b = to_bytes(); return b[ 0] == 0 && b[ 1] == 0 && b[ 2] == 0 && b[ 3] == 0 && b[ 4] == 0 && b[ 5] == 0 && b[ 6] == 0 && b[ 7] == 0 && b[ 8] == 0 && b[ 9] == 0 && b[10] == 0 && b[11] == 0 && b[12] == 0 && b[13] == 0 && b[14] == 0 && b[15] == 0;
constexpr bool is_loopback() const noexcept;
Returns: A boolean indicating whether the
address_v6
object represents a loopback address, as if computed by the following method:bytes_type b = to_bytes(); return b[ 0] == 0 && b[ 1] == 0 && b[ 2] == 0 && b[ 3] == 0 && b[ 4] == 0 && b[ 5] == 0 && b[ 6] == 0 && b[ 7] == 0 && b[ 8] == 0 && b[ 9] == 0 && b[10] == 0 && b[11] == 0 && b[12] == 0 && b[13] == 0 && b[14] == 0 && b[15] == 1;
constexpr bool is_multicast() const noexcept;
Returns: A boolean indicating whether the
address_v6
object represents a multicast address, as if computed by the following method:bytes_type b = to_bytes(); return b[0] == 0xFF;
constexpr bool is_link_local() const noexcept;
Returns: A boolean indicating whether the
address_v6
object represents a unicast link-local address, as if computed by the following method:bytes_type b = to_bytes(); return b[0] == 0xFE && (b[1] & 0xC0) == 0x80;
constexpr bool is_site_local() const noexcept;
Returns: A boolean indicating whether the
address_v6
object represents a unicast site-local address, as if computed by the following method:bytes_type b = to_bytes(); return b[0] == 0xFE && (b[1] & 0xC0) == 0xC0;
constexpr bool is_v4_mapped() const noexcept;
Returns: A boolean indicating whether the
address_v6
object represents an IPv4-mapped IPv6 address, as if computed by the following method:bytes_type b = to_bytes(); return b[ 0] == 0 && b[ 1] == 0 && b[ 2] == 0 && b[ 3] == 0 && b[ 4] == 0 && b[ 5] == 0 && b[ 6] == 0 && b[ 7] == 0 && b[ 8] == 0 && b[ 9] == 0 && b[10] == 0xFF && b[11] == 0xFF;
constexpr bool is_multicast_node_local() const noexcept;
Returns: A boolean indicating whether the
address_v6
object represents a multicast node-local address, as if computed by the following method:bytes_type b = to_bytes(); return b[0] == 0xFF && (b[1] & 0x0F) == 0x01;
constexpr bool is_multicast_link_local() const noexcept;
Returns: A boolean indicating whether the
address_v6
object represents a multicast link-local address, as if computed by the following method:bytes_type b = to_bytes(); return b[0] == 0xFF && (b[1] & 0x0F) == 0x02;
constexpr bool is_multicast_site_local() const noexcept;
Returns: A boolean indicating whether the
address_v6
object represents a multicast site-local address, as if computed by the following method:bytes_type b = to_bytes(); return b[0] == 0xFF && (b[1] & 0x0F) == 0x05;
constexpr bool is_multicast_org_local() const noexcept;
Returns: A boolean indicating whether the
address_v6
object represents a multicast organisation-local address, as if computed by the following method:bytes_type b = to_bytes(); return b[0] == 0xFF && (b[1] & 0x0F) == 0x08;
constexpr bool is_multicast_global() const noexcept;
Returns: A boolean indicating whether the
address_v6
object represents a multicast global address, as if computed by the following method:bytes_type b = to_bytes(); return b[0] == 0xFF && (b[1] & 0x0F) == 0x0E;
constexpr bytes_type to_bytes() const noexcept;
Returns: A representation of the address in network byte order.
string to_string() const; string to_string(error_code& ec) const;
Effects: Converts an address into a string representation. If
scope_id() == 0
, converts as if by POSIXinet_ntop()
when invoked with address familyAF_INET6
. Ifscope_id() != 0
, the format isaddress
%
scope-id
, whereaddress
is the string representation of the equivalent address havingscope_id() == 0
, andscope-id
is an implementation-defined string representation of the scope identifier.
Returns: If successful, the string representation of the address. Otherwise
string()
.
static constexpr address_v6 any() noexcept;
Returns:
address_v6()
.
static constexpr address_v6 loopback() noexcept;
Returns: An address
a
such that the conditiona.is_loopback()
holds.
bool operator==(const address_v6& a, const address_v6& b) noexcept;
Returns:
a.to_bytes() == b.to_bytes() && a.scope_id() == b.scope_id()
.
bool operator!=(const address_v6& a, const address_v6& b) noexcept;
Returns:
!(a == b)
.
bool operator< (const address_v6& a, const address_v6& b) noexcept;
Returns:
a.to_bytes() < b.to_bytes() || (!(b.to_bytes() < a.to_bytes()) && a.scope_id() < b.scope_id())
.
bool operator> (const address_v6& a, const address_v6& b) noexcept;
Returns:
b < a
.
bool operator<=(const address_v6& a, const address_v6& b) noexcept;
Returns:
!(b < a)
.
bool operator>=(const address_v6& a, const address_v6& b) noexcept;
Returns:
!(a < b)
.
constexpr address_v6 make_address_v6(const address_v6::bytes_type& bytes, unsigned long scope_id);
Returns:
address_v6(bytes, scope_id)
.
constexpr address_v6 make_address_v6(v4_mapped_t, const address_v4& a) noexcept;
Returns: An
address_v6
object containing the IPv4-mapped IPv6 address corresponding to the specified IPv4 address, as if computed by the following method:address_v4::bytes_type v4b = a.to_bytes(); bytes_type v6b(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, v4b[0], v4b[1], v4b[2], v4b[3]); return address_v6(v6b);
address_v6 make_address_v6(const char* str); address_v6 make_address_v6(const char* str, error_code& ec) noexcept; address_v6 make_address_v6(const string& str); address_v6 make_address_v6(const string& str, error_code& ec) noexcept;
Effects: Converts a string representation of an address into a corresponding
address_v6
value. The format is eitheraddress
oraddress
%
scope-id
, whereaddress
is in the format specified by POSIXinet_pton()
when invoked with address familyAF_INET6
, andscope-id
is an optional string specifying the scope identifier. All implementations shall accept asscope-id
a string representation of an unsigned decimal integer. It is implementation-defined whether alternative scope identifier representations are permitted. Ifscope-id
is not supplied, anaddress_v6
object shall be returned such thatscope_id() == 0
.
Returns: If successful, an
address_v6
value corresponding to the stringstr
. Otherwise returnsaddress_v6()
.
template<class CharT, class Traits> basic_ostream<CharT, Traits>& operator<<( basic_ostream<CharT, Traits>& os, const address_v6& addr);
Effects: Outputs the string representation of the address to the stream, as if it were implemented as follows:
error_code ec; string s = addr.to_string(ec); if (ec) { if (os.exceptions() & ios_base::failbit) throw system_error(ec); else os.setstate(ios_base::failbit); } else for (string::iterator i = s.begin(); i != s.end(); ++i) os << os.widen(*i);
Returns:
os
.
namespace std { namespace experimental { namespace net { namespace ip { class bad_address_cast : bad_cast { public: virtual const char* what() const noexcept; }; } // namespace ip } // namespace net } // namespace experimental } // namespace std
Objects of type bad_address_cast
are thrown by a failed address_cast
.
template <class T> constexpr T address_cast(const address& a) noexcept(see below);
This function template shall participate in overload resolution only for the types
T
listed in the table below.
Table 4. template <class T> constexpr T address_cast(const address&) effects
T |
noexcept |
remarks |
---|---|---|
|
|
Returns |
|
|
If |
|
|
If |
template <class T> constexpr T address_cast(const address_v4& a) noexcept(see below);
This function template shall participate in overload resolution only for the types
T
listed in the table below.
Table 5. template <class T> constexpr T address_cast(const address_v4&) effects
T |
noexcept |
remarks |
---|---|---|
|
|
Returns a version-independent |
|
|
Returns |
|
Function overload is deleted. |
template <class T> constexpr T address_cast(const address_v6& a) noexcept(see below);
This function template shall participate in overload resolution only for the types
T
listed in the table below.
Table 6. template <class T> constexpr T address_cast(const address_v6&) effects
T |
noexcept |
remarks |
---|---|---|
|
|
Returns a version-independent |
|
Function overload is deleted. | |
|
|
Returns |
template <> struct hash<net::ip::address>; template <> struct hash<net::ip::address_v4>; template <> struct hash<net::ip::address_v6>;
Requires: the template specializations shall meet the requirements of class template
hash
(C++14 [unord.hash]).
This section describes literal suffixes for constructing address literals.
The suffixes ip
, ipv4
and ipv6
denote address values of the corresponding types ip::address
,
ip::address_v4
and ip::address_v6
respectively if they are applied to string literals.
[Example: The following code shows some address literals.
using namespace std::experimental::net_literals; auto addr = "127.0.0.1"ip; auto v4_addr = "255.255.255.255"ipv4; auto v6_addr = "::1"ipv6;
—end example]
net::ip::address operator "" ip(const char* str, size_t);
Returns:
net::ip::make_address(str)
.
net::ip::address_v4 operator "" ipv4(const char* str, size_t);
Returns:
net::ip::make_address_v4(str)
.
net::ip::address_v6 operator "" ipv6(const char* str, size_t);
Returns:
net::ip::make_address_v6(str)
.
In this revision of the proposal, we include changes made based on feedback and discussion from the 2013 meeting of SG4 at Bristol, where N3603 was discussed.
This revision moves the proposed types and functions from the std::
namespace
to std::experimental::
.
The ip::address
class has been modified so that
the version-specific types do not appear in its interface. An approach based
on the any
class has been
adopted (see Library Fundamentals working draft), and address types may be
explicitly converted using the address_cast<>
function. The version-specific types
are implicitly convertible to ip::address
via a template constructor.
For example:
address_v4 a; address b = a; // ok, implicit conversion address c = address_cast<address>(a); // ok, explicit conversion address_v4 d = address_cast<address_v4>(b); // ok, explicit conversion address_v6 e = address_cast<address_v6>(b); // invalid, throws bad_address_cast
This replaces the from_string()
static member functions with new free functions
make_address()
,
make_address_v4()
and make_address_v6()
.
These functions allow explicit creation of the address types from strings
and other types, such as an array of bytes or an integer in host byte order.
For example, one overload throws an exception on failure:
address_v4 a = make_address_v4("127.0.0.1"); // succeeds address_v4 b = make_address_v4("::1"); // throws
and another overload provides a non-throwing alternative:
error_code ec; address_v4 b = make_address_v4("127.0.0.1", ec); // succeeds, clears ec address_v4 b = make_address_v4("::1", ec); // sets ec
An explicit template constructor has been added to also support this style of use:
address c("127.0.0.1");
This constructor simply forwards the arguments to the appropriate make_address()
overload.
Support for IP address literals has been included. For example:
using namespace std::experimental::net_literals; auto addr = "127.0.0.1"ip; auto v4_addr = "255.255.255.255"ipv4; auto v6_addr = "::1"ipv6;
The nested typedefs bytes_type
have been changed to be unique standard-layout types. Objects of type bytes_type
are implicitly convertible to
the corresponding address class. This is intended to support the following
use case, where the byte representations of addresses are included as part
of a larger standard-layout structure, such as a packet definition:
struct header { address_v4::bytes_type from; address_v4::bytes_type to; // ... }; struct message { header hdr; // ... }; // ... address_v4 old_address = "1.2.3.4"ipv4; address_v4 new_address = "4.3.2.1"ipv4; message m; receive_message(m); // e.g. reads bytes from a socket if (m.hdr.to == old_address) m.hdr.to = new_address.to_bytes();
The constexpr
keyword has
been applied to some of the functions in the proposal. The rationale for
this change is that many of the equivalent POSIX macros
can be used in constant expressions.
A default-constructed address
object now represents an invalid address that is neither IPv4 nor IPv6. Any
attempt to address_cast
it
to another type will result in a bad_address_cast
exception.
The author would like to thank Arash Partow, Jamie Allsop, James Anderson and Kyle Kloepper for their feedback and suggestions.
[RFC4291] Hinden, R. and Deering, S., RFC 4291: Internet Protocol Version 6 (IPv6) Addressing Architecture, 2006, http://www.ietf.org/rfc/rfc4291.txt.