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)
这更好地匹配意图,编写的代码更少,并且编译器在重载解析期间要做的工作更少(因为必须在两者之间进行选择的构造函数更少)。
我看到的另一种可能的用法是使用可变参数模板:
默认情况下,通常是好的explicit(除非需要转换)。
所以
struct Foo
{
template <typename ... Ts>
explicit(sizeof...(Ts) == 1) Foo(Ts&&...);
// ...
};
Run Code Online (Sandbox Code Playgroud)
我可以看到一个用例,explicit当输入可能是类似视图的类型(原始指针std::string_view)时,新对象将在调用后保留该类型(仅复制视图,而不是它引用的内容,仍然依赖于所查看对象的生命周期),或者它可能是类似值的类型(获取副本的所有权,没有外部生命周期依赖性)。
在这种情况下,调用者负责保持所查看的对象处于活动状态(被调用者拥有视图,而不是原始对象),并且转换不应该隐式完成,因为这使得隐式创建的对象太容易被破坏。比它所看到的对象更长寿。相比之下,对于值类型,新对象将接收自己的副本,因此虽然副本可能成本高昂,但如果发生隐式转换,它不会使代码错误。
| 归档时间: |
|
| 查看次数: |
1795 次 |
| 最近记录: |