Sama motywacja znajduje się w artykule .
Istnieje potrzeba, aby konstruktory były warunkowo jawne. Oznacza to, że chcesz:
pair<string, string> safe() {
return {"meow", "purr"}; // ok
}
pair<vector<int>, vector<int>> unsafe() {
return {11, 22}; // error
}
To pierwsze jest w porządku, te konstruktory są ukryte. Ale to drugie byłoby złe, ci konstruktorzy są explicit
. W C ++ 17 (lub C ++ 20 z koncepcjami) jedynym sposobem na wykonanie tej pracy jest napisanie dwóch konstruktorów - jednego explicit
i jednego nie:
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&& );
};
Są one prawie całkowicie zduplikowane - a definicje tych konstruktorów byłyby identyczne.
Za pomocą explicit(bool)
możesz napisać tylko jednego konstruktora - z warunkowo jawną częścią konstrukcji zlokalizowaną tylko na 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&& );
};
To lepiej pasuje do zamiaru, jest o wiele mniej kodu do napisania i jest mniej pracy dla kompilatora podczas rozwiązywania problemu przeciążenia (ponieważ jest mniej konstruktorów do wyboru).
tuple
z tą funkcją.