限制std :: optional的转发参考构造函数 [英] Constraint on std::optional's forwarding reference constructor

查看:68
本文介绍了限制std :: optional的转发参考构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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 neither std::in_place_t nor std::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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆