显式 (bool) 的用例是什么

NKA*_*KAR 23 c++ explicit c++20

C++20 引入了显式 (bool),它在编译时有条件地选择构造函数是否显式。

下面是我在这里找到的一个例子。

struct foo {

  // Specify non-integral types (strings, floats, etc.) require explicit construction.

  template <typename T>

  explicit(!std::is_integral_v<T>) foo(T) {}

};

foo a = 123; // OK

foo b = "123"; // ERROR: explicit constructor is not a candidate (explicit specifier evaluates to true)

foo c {"123"}; // OK
Run Code Online (Sandbox Code Playgroud)

谁能告诉我explicit (bool)除了 using 之外的任何其他用例std::is_integral

Bar*_*rry 21

动机本身可以在论文中看到。

需要使构造函数有条件地显式。也就是说,你想要:

pair<string, string> safe() {
    return {"meow", "purr"}; // ok
}

pair<vector<int>, vector<int>> unsafe() {
    return {11, 22}; // error
}
Run Code Online (Sandbox Code Playgroud)

前者很好,那些构造函数是隐式的。但后者会很糟糕,那些构造函数是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&& );    
};  
Run Code Online (Sandbox Code Playgroud)

这些几乎完全重复 - 这些构造函数的定义将是相同的。

使用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&& );   
};
Run Code Online (Sandbox Code Playgroud)

这更好地匹配意图,编写的代码更少,并且编译器在重载解析期间要做的工作更少(因为必须在两者之间进行选择的构造函数更少)。


Jar*_*d42 7

我看到的另一种可能的用法是使用可变参数模板:

默认情况下,通常是好的explicit(除非需要转换)。

所以

struct Foo
{
    template <typename ... Ts>
    explicit(sizeof...(Ts) == 1) Foo(Ts&&...);

    // ...
};
Run Code Online (Sandbox Code Playgroud)


Sha*_*ger 0

我可以看到一个用例,explicit当输入可能是类似视图的类型(原始指针std::string_view)时,新对象将在调用后保留该类型(仅复制视图,而不是它引用的内容,仍然依赖于所查看对象的生命周期),或者它可能是类似值的类型(获取副本的所有权,没有外部生命周期依赖性)。

在这种情况下,调用者负责保持所查看的对象处于活动状态(被调用者拥有视图,而不是原始对象),并且转换不应该隐式完成,因为这使得隐式创建的对象太容易被破坏。比它所看到的对象更长寿。相比之下,对于值类型,新对象将接收自己的副本,因此虽然副本可能成本高昂,但如果发生隐式转换,它不会使代码错误。