限制std :: optional的转发参考构造函数 [英] Constraint on std::optional's forwarding reference constructor
问题描述
std :: optional
具有8个构造函数,列在下面(也在此处 http://en.cppreference.com/w/cpp/utility/optional/optional )
std::optional
has 8 constructors as of this date, listed below (also here http://en.cppreference.com/w/cpp/utility/optional/optional)
/* (1) */ constexpr optional() noexcept;
/* (1) */ constexpr optional( std::nullopt_t ) noexcept;
/* (2) */ constexpr optional( const optional& other );
/* (3) */ constexpr optional( optional&& other ) noexcept(/* see below */);
template < class U >
/* (4) */ /* EXPLICIT */ optional( const optional<U>& other );
template < class U >
/* (5) */ /* EXPLICIT */ optional( optional<U>&& other );
template< class... Args >
/* (6) */ constexpr explicit optional( std::in_place_t, Args&&... args );
template< class U, class... Args >
/* (7) */ constexpr explicit optional( std::in_place_t,
std::initializer_list<U> ilist,
Args&&... args );
template < class U = value_type >
/* (8) */ /* EXPLICIT */ constexpr optional( U&& value );
我喜欢最后一个构造函数.它有助于 std :: optional
从cv-ref合格引用构造为 Type
类型.超级方便.
I like the last constructor. It helps std::optional
to be constructed from cv-ref qualified references to type Type
. Which is super convenient.
除此之外,最后一个构造函数也有帮助,因为它是使用列表初始化来初始化 std :: optional
实例的便捷方法,而不必使用 std :: in_place
.发生这种情况的原因是,当将花括号括起来的参数列表传递给构造函数时,使用默认类型,因为函数模板无法从 {}
推断出类型(至少这是我对情况的理解)这是我最近才学到的一种巧妙技巧(也请注意,根据此处
Other than that, the last constructor also helps because it is a convenient way to use list initialization to initialize the std::optional
instance, without having to use std::in_place
. This happens because when a curly brace enclosed argument list is passed to the constructor, the default type is used because the function template cannot deduce a type from the {}
(at least that is my understanding of the situation and is a neat trick I picked up only recently) (also note that this can only be used to call non explicit constructors of the underlying type, as per the rules here http://en.cppreference.com/w/cpp/language/list_initialization)
auto optional = std::optional<std::vector<int>>{{1, 2, 3, 4}};
我能理解的最后一个构造函数有两个约束
There are two constraints on the last constructor that I can understand
-
std :: decay_t< U>
既不是std :: in_place_t
也不是std :: optional< T>
- 仅当
std :: is_convertible_v< U&& ;, T>
为false 时,此构造函数才是显式的.
std::decay_t<U>
is neitherstd::in_place_t
norstd::optional<T>
- This constructor is explicit if and only if
std::is_convertible_v<U&&, T>
is false
第一个很容易理解,它有助于防止构造函数(2),(3),(4),(5),(6)和(7)产生歧义.如果类型为 std :: in_place
,则可能与(6)和(7)冲突.如果类型是 std :: optional
的实例化,则它可能与(2),(3),(4)和(5)冲突.
The first is easy to understand, it helps prevent against ambiguities with constructors (2), (3), (4), (5), (6) and (7). If the type is std::in_place
it can conflict with (6) and (7). If the type is an instantiation of std::optional
then it can conflict with (2), (3), (4) and (5).
第二个只是将基础类型的构造函数的显式性转发"为可选
类型
The second just "forwards" the explicitness of the constructor of the underlying type to the optional
type
但是第三个限制很好奇
- 除非
std :: is_constructible_v< T,U&&
为真,否则该构造函数不参与重载解析.
- This constructor does not participate in overload resolution unless
std::is_constructible_v<T, U&&>
is true
为什么需要这个?(8)永远不会与空构造函数冲突,因为它至少需要一个参数.这只剩下一个原因-在传递 std :: nullopt
时可能与 std :: nullopt_t
发生冲突,但这不会发生,因为 nullopt
版本始终是更好的匹配,无论传递了 std :: nullopt_t
的cv-ref合格版本(如下所示)
Why is this needed? (8) can never conflict with the empty constructor because it needs at least one argument. That leaves only one left reason - it might conflict with std::nullopt_t
when passed std::nullopt
, but that will not happen because the nullopt
version is always a better match no matter what cv-ref qualified version of std::nullopt_t
is passed (as demonstrated below)
void func(int) {
cout << __PRETTY_FUNCTION__ << endl;
}
template <typename U>
void func(U&&) {
cout << __PRETTY_FUNCTION__ << endl;
}
int main() {
auto i = int{1};
func(1);
func(i);
func(std::move(i));
func(std::as_const(i));
func(std::move(std::as_const(i)));
}
最后一个限制的原因是什么?
What is the reason behind the last restriction?
为什么不仅仅让构造函数像往常一样出错?是否需要通过SFINAE传递的参数来帮助检测该类型是否可构造而不会在以后导致硬错误?
Why not just let the constructor error out as usual? Is this needed to help detect if the type is constructible via an argument passed via SFINAE without causing a hard error later?
推荐答案
说谎特质不好.
基本词汇类型的说谎特质是不好的.
Lying traits for a fundamental vocabulary type are plusungood.
也很容易干扰重载解析的基本词汇类型的特质是doubleplusungood.
Lying traits for a fundamental vocabulary type that can also easily interfere with overload resolution are doubleplusungood.
void f(std::optional<int>);
void f(std::optional<const char*>);
f({""}); // ambiguous without the constraint
这篇关于限制std :: optional的转发参考构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!