동기 부여 자체는 논문 에서 볼 수있다 .
생성자를 조건부로 명시 적으로 만들어야합니다. 즉, 당신은 원합니다 :
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
-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&& );
};
이것은 의도와 더 잘 일치하고 작성하는 코드가 훨씬 적으며 과부하 해결 중에 컴파일러가 수행 할 작업이 적습니다 (선택해야 할 생성자가 적기 때문에).
tuple
이 기능 을 사용 하는 것과 같은 조건부 명시 적 생성자를 구현하는 것이 훨씬 쉬워진다는 것 입니다.