Die Motivation selbst ist in der Zeitung zu sehen .
Konstruktoren müssen bedingt explizit gemacht werden. Das heißt, Sie wollen:
pair<string, string> safe() {
return {"meow", "purr"}; // ok
}
pair<vector<int>, vector<int>> unsafe() {
return {11, 22}; // error
}
Ersteres ist in Ordnung, diese Konstruktoren sind implizit. Aber letzteres wäre schlecht, diese Konstruktoren sind es explicit
. Mit C ++ 17 (oder C ++ 20 mit Konzepten) können Sie diese Funktion nur ausführen, indem Sie zwei Konstruktoren schreiben - einen explicit
und einen nicht:
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&& );
};
Diese sind fast vollständig dupliziert - und die Definitionen dieser Konstruktoren wären identisch.
Mit explicit(bool)
können Sie einfach einen einzelnen Konstruktor schreiben - wobei der bedingt explizite Teil der Konstruktion nur auf den explicit
-specifier beschränkt ist:
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&& );
};
Dies entspricht der Absicht besser, ist viel weniger Code zum Schreiben und weniger Arbeit für den Compiler während der Überlastungsauflösung (da weniger Konstruktoren zur Auswahl stehen).
tuple
mit dieser Funktion zu implementieren .