optional适合用于函数返回值,当返回值为空时,optional将不会消耗额外的内存空间。
构造:
std::optional op = std::nullopt;
std::optional op1 = { "123" };
// std::in_place指明直接调用std::string("consruct")构造std::string对象
std::optional op3(std::in_place, "construct");
std::cout << op.value_or(0) << *op1 << op3.value() << std::endl;
举例:
#include
#include
#include
std::optional maybe_getenv(const char* n)
{
if(const char* x = std::getenv(n))
return x;
else
return {}; // 也可以使用 std::nullopt;
}
int main()
{
// maybe_getenv("MYPWD")函数取环境变量MYPWD的值
// value_or("(none)") 表示若为空值,则取默认值(none)
std::cout << maybe_getenv("MYPWD").value_or("(none)") << '\n';
}
适用于想保存多个值的情况,省去声明结构体的麻烦。
// tuple的一些构造方法
std::tuple t1;
std::tuple t2(42, "Test", -3.14);
std::tuple t3(t2);
std::tuple t4(std::make_pair(42, 3.14));
// std::tie 可以用来作为std::tuple的左值引用,也可以用来解包
int a, b;
// std::tie(a,b)类型其实就是std::tuple,即左值引用
// 以下操作会使 a = 1, b = 2,即解包
std::tie(a, b) = std::pair(1, 2);
cout << a << " " << b << endl; // 1 2
// 若解包时有些变量不想要,则可使用std::ingore
std::tie(a, b, std::ignore) = std::tuple(2, 4, 6);
cout << a << " " << b << endl; // 2 4
// std::tuple_cat用于连接多个tuple
auto tup = std::tuple_cat(t2, t4);
print(tup);// (42, "Test", -3.14, 42, 3.14)
// 使用std::get取值
cout << std::get<0>(t2) << endl; // 42
cout << std::get(t2) << endl; // Test
// 注意 std::get(t2) 必须是t2里只含有一个string类型时才可以
std::tuple的特例,只保存两个
可以保存任意类型数据,使用any_cast转换类型,转换失败可捕获bad_any_cast异常,对象需是可复制的
#include
#include
int main()
{
std::cout << std::boolalpha;
// any type
std::any a = 1;
std::cout << a.type().name() << ": " << std::any_cast(a) << '\n';
a = 3.14;
std::cout << a.type().name() << ": " << std::any_cast(a) << '\n';
a = true;
std::cout << a.type().name() << ": " << std::any_cast(a) << '\n';
// bad cast
try
{
a = 1;
std::cout << std::any_cast(a) << '\n';
}
catch (const std::bad_any_cast& e)
{
std::cout << e.what() << '\n';
}
// has value
a = 1;
if (a.has_value())
{
std::cout << a.type().name() << '\n';
}
// reset
a.reset();
if (!a.has_value())
{
std::cout << "no value\n";
}
// pointer to contained data
a = 1;
int* i = std::any_cast(&a);
std::cout << *i << "\n";
}
/*
i: 1
d: 3.14
b: true
bad any_cast
i
no value
1
*/
以std::tuple作为参数调用callable函数,std::array,std::pair也可替代std::tuple使用
#include
#include
#include
int add(int first, int second) { return first + second; }
template
T add_generic(T first, T second) { return first + second; }
auto add_lambda = [](auto first, auto second) { return first + second; };
template
std::ostream& operator<<(std::ostream& os, std::tuple const& theTuple)
{
std::apply
(
[&os](Ts const&... tupleArgs)
{
os << '[';
std::size_t n{0};
((os << tupleArgs << (++n != sizeof...(Ts) ? ", " : "")), ...);
os << ']';
}, theTuple
);
return os;
}
int main()
{
// OK
std::cout << std::apply(add, std::pair(1, 2)) << '\n';
// 错误:无法推导函数类型
// std::cout << std::apply(add_generic, std::make_pair(2.0f, 3.0f)) << '\n';
// OK
std::cout << std::apply(add_lambda, std::pair(2.0f, 3.0f)) << '\n';
// 进阶示例
std::tuple myTuple(25, "Hello", 9.31f, 'c');
std::cout << myTuple << '\n';
}
/*
3
5
[25, Hello, 9.31, c]
*/
一个类型安全的联合体(union),非法访问时抛出bad_variant_access异常
varrant变量只能多次保存或赋值同一类型的值,或者不同cv限定符但同一类型的值
std::monostate可以让类或结构体默认构造对象(即使没有默认构造函数)
std::visit是为了访问variant变量而定制的接口
holds_alternative检测是否含有某个类型的值
std::get(std::variant)用来访问值
#include
#include
/* 声明多个重载*/
template struct overloaded : Ts... { using Ts::operator()...; };
template overloaded(Ts...)->overloaded;
int main(int argc, char* argv[])
{
struct VarT {
VarT(int i) {}
int i;
};
std::variant var, var1, var2, var3;
var = "123"; // ok
var = "234"; // ok
//var = 1; // error
/* 构造没有默认构造函数类型的对象 */
std::variant var4;
/* 判断是否存在该类型 */
cout << std::holds_alternative(var) << endl; // false
cout << std::holds_alternative(var) << endl; // true
/* 取值 下标从0开始 */
cout << std::get(var) << endl;
cout << std::get<3>(var) << endl;
try {
cout << std::get<1>(var) << endl; // throw exception
}
catch (std::bad_variant_access& e) {
cout << e.what() << endl;
}
/* 使用函数直接访问 */
std::visit([](auto && v) {
cout << v << endl;
}, var);
var2 = 1.5;
var3 = 4;
/* 使用重载的lambdas函数,会选择最优匹配的执行 */
std::visit(overloaded{
[](auto arg) { std::cout << arg << ' '; },
[](double arg) { std::cout << std::fixed << arg << ' '; },
[](const std::string& arg) { std::cout << arg << ' '; },
}, var);
std::visit(overloaded{
[](auto arg) { std::cout << arg << ' '; },
[](double arg) { std::cout << std::fixed << arg << ' '; },
[](const std::string& arg) { std::cout << arg << ' '; },
}, var2);
/* 还可使用类对象,重载operator() */
/* 还可使用泛型lambdas */
auto visitor = [](const auto& val){
std::cout << val << std::endl;
};
std::visit(visitor, var3);
return 0;
}
使用tuple来构造对象。
struct mt {
mt(int i, std::string str) {}
};
mt eg = std::make_from_tuple(std::tuple{1, "test"});