关于 std::variant 中三个构造函数的问题
Questions about three constructors in std::variant's proposed interface
为什么std::variant
从http://en.cppreference.com/w/cpp/utility/variant/variant存在构造函数(4)?这似乎会在代码中造成很多歧义,否则可以通过显式来避免这些歧义。例如,cppreference上的代码示例突出了用户可能没有注意到的可能的歧义(第三行)
variant<string> v("abc"); // OK
variant<string, string> w("abc"); // ill-formed, can't select the alternative to convert to
variant<string, bool> w("abc"); // OK, but chooses bool
在某些情况下,它是绝对需要的吗?
另一个问题是为什么构造函数(6)和(8)需要来自同一个cppreference页面。(5)和(7)难道不能达到(6)和(8)的目的吗?我可能误解了它们的用法。
对于读者,我在问题中提到的构造函数是
constexpr variant(); // (1) (since C++17)
variant(const variant& other); // (2) (since C++17)
variant(variant&& other); // (3) (since C++17)
template< class T > // (4) (since C++17)
constexpr variant(T&& t);
template< class T, class... Args >
constexpr explicit variant(std::in_place_type_t<T>, Args&&... args); // (5) (since C++17)
template< class T, class U, class... Args >
constexpr explicit variant(std::in_place_type_t<T>,
std::initializer_list<U> il, Args&&... args); // (6) (since C++17)
template< std::size_t I, class... Args >
constexpr explicit variant(std::in_place_index_t<I>, Args&&... args) // (7) (since C++17)
template <size_t I, class U, class... Args>
constexpr explicit variant(std::in_place_index_t<I>,
std::initializer_list<U> il, Args&&... args); // (8) (since C++17)
在某些情况下,它是绝对需要的吗?
。但这些东西不会增加,因为它们"绝对会被需要"。它们被添加是因为它们有用。
从它的一个组件类型隐式转换对于variant
是非常有用的。是的,它在某些极端情况下造成了歧义。但是这种歧义通常是由于类型设计的缺陷造成的(比如字符串字面值倾向于转换为bool
而不是用户定义的转换)。
如果有一个不明确的情况,那么你必须明确它。比如使用"abc"s
UDL字面量而不是裸字符串字面量(这样做的另一个原因)。但是,当你处理设计良好的类型时,没有理由强迫每个都是显式的。
(5)和(7)不能达到(6)和(8)的目的吗?
不合理。
在标准中的每种情况下,当函数接受将传递给构造函数的可变参数时,它们将在该对象上使用构造函数语法而不是{}
语法。所以如果你有这个:
using type = vector<int>;
variant<type> t(in_place<type>, 6);
您将接到vector<int>(6)
的呼叫。注意,这与vector<int>{6}
不同。也就是说,除非你实际传递了一个初始化列表,否则你不会得到初始化列表构造函数。
现在,你可以这样做:
variant<type> t(in_place<type>, initializer_list<int>{6});
但是这太啰嗦了。相比之下:
variant<type> t(in_place<type>, {6});
这样就没那么啰嗦了。编译器可以推断出初始化列表的类型。然而,如果您试图将braced-init-list
推断为任意T
,则模板参数类型推断会失败。
模板演绎与auto
演绎的不同之处在于,它不从braced-init-list
表达式中演绎initializer_list
s。例如
template <typename Type>
void func(const Type&);
对于下面的调用
, 不会将Type
推断为std::initializer_list
func({1, 2, 3, 4, 5});
要了解更多信息,请参见通用引用和std::initializer_list。
- 用相同的参数声明两个构造函数的最偶像化的方法是什么?
- 我的动态链接队列在同一输出流中调用时不正确地输出三个返回函数
- 静态类属性,C++中的多个构造函数
- 如何通过通用引用或std::forward将这三个c++模板函数合并为一个
- 如何同时创建一个具有两个或多个构造函数初始化的对象
- pair的两个构造函数几乎相同,为什么不生成构建错误?
- 为什么<T> LLVM 中的预期为 Expect&&... 实现两个构造函数<T>?
- 如何通过可变参数模板将多个构造函数参数转发到数组初始值设定项列表?
- 三个参数函数模板令人困惑的示例
- C++,处理多个构造函数重载和冗余代码
- 在第三个 pary 函数中使用矢量引用时出现意外错误
- 父类有 26 个构造函数重载.如何在不复制+粘贴 26 个重载的情况下将一个小任务附加到所有构造器?
- 如何在C 中的单个构造函数中调用多个构造函数
- 为什么我的类只适用于两个构造函数 C++
- C++创建多个构造函数
- 需要为派生类指定多少个构造函数
- 访问三个不同的变量在C++中形成三个不同函数中的一个文件
- 具有三个构造函数的矩形类
- 这三个构造函数的区别是什么?
- 关于 std::variant 中三个构造函数的问题