optional、tuple、any、variant

std::optional

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';
}

std::tuple

适用于想保存多个值的情况,省去声明结构体的麻烦。

    // 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::pair

std::tuple的特例,只保存两个

std::any

可以保存任意类型数据,使用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::apply

以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]
*/

std::variant

一个类型安全的联合体(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;
}

std::make_from_tuple

使用tuple来构造对象。

struct mt {
	mt(int i, std::string str) {}
};
mt eg = std::make_from_tuple(std::tuple{1, "test"});

 

 

你可能感兴趣的:(c++,c++)