Саму мотивацію можна побачити у статті .
Необхідно зробити конструктори умовно явними. Тобто ви хочете:
pair<string, string> safe() {
return {"meow", "purr"}; // ok
}
pair<vector<int>, vector<int>> unsafe() {
return {11, 22}; // error
}
Перше добре, ті конструктори неявні. Але останнє було б погано, такі конструктори є explicit
. Для C ++ 17 (або C ++ 20 з поняттями) єдиний спосіб зробити цю роботу - написати два конструктори - один explicit
і один не:
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&& );
};
Вони майже повністю дублюються - і визначення цих конструкторів були б ідентичними.
З explicit(bool)
, ви можете просто написати один конструктор - із умовно явною частиною конструкції, локалізованою лише на explicit
-специфікаторі:
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&& );
};
Це краще відповідає намірам, набагато менше коду для запису і менше роботи компілятору для виконання під час вирішення перевантаження (оскільки менше конструкторів потрібно вибирати між).
tuple
цієї функції.