Động lực chính nó có thể được nhìn thấy trong bài báo .
Có một nhu cầu để làm cho các nhà xây dựng có điều kiện rõ ràng. Đó là, bạn muốn:
pair<string, string> safe() {
return {"meow", "purr"}; // ok
}
pair<vector<int>, vector<int>> unsafe() {
return {11, 22}; // error
}
Các cựu là tốt, những nhà xây dựng là ẩn. Nhưng sau này sẽ là xấu, những nhà xây dựng là explicit
. Với C ++ 17 (hoặc C ++ 20 với các khái niệm), cách duy nhất để thực hiện công việc này là viết hai hàm tạo - một explicit
và một không:
template <typename T1, typename T2>
struct pair {
template <typename U1=T1, typename U2=T2,
std::enable_if_t<
std::is_constructible_v<T1, U1> &&
std::is_constructible_v<T2, U2> &&
std::is_convertible_v<U1, T1> &&
std::is_convertible_v<U2, T2>
, int> = 0>
constexpr pair(U1&&, U2&& );
template <typename U1=T1, typename U2=T2,
std::enable_if_t<
std::is_constructible_v<T1, U1> &&
std::is_constructible_v<T2, U2> &&
!(std::is_convertible_v<U1, T1> &&
std::is_convertible_v<U2, T2>)
, int> = 0>
explicit constexpr pair(U1&&, U2&& );
};
Chúng gần như hoàn toàn trùng lặp - và định nghĩa của các hàm tạo này sẽ giống hệt nhau.
Với explicit(bool)
, bạn chỉ có thể viết một hàm tạo duy nhất - với phần rõ ràng có điều kiện của cấu trúc được bản địa hóa thành chỉ explicit
-specifier:
template <typename T1, typename T2>
struct pair {
template <typename U1=T1, typename U2=T2,
std::enable_if_t<
std::is_constructible_v<T1, U1> &&
std::is_constructible_v<T2, U2>
, int> = 0>
explicit(!std::is_convertible_v<U1, T1> ||
!std::is_convertible_v<U2, T2>)
constexpr pair(U1&&, U2&& );
};
Điều này phù hợp với ý định tốt hơn, viết mã ít hơn nhiều và công việc của trình biên dịch sẽ ít hơn trong quá trình giải quyết quá tải (vì có ít hàm tạo hơn phải chọn giữa).
tuple
với tính năng này.