in_place用法
c++中有三个类似于c语言中union一样的类型,分别为
cpp-reference optional
类模板 std::optional 管理一个可选的容纳值,既可以存在也可以不存在的值。可以有值或者nullopt。一般用作返回值,
具体常用的函数看如下代码
#include
#include
#include
#include
#include
using namespace std;
class T
{
public:
T(int i):a(i){cout<<"the value is "<<i<<endl;}
T(T&& t){cout<<"this is move"<<endl;}
T(const T& t)=default;
friend ostream& operator<<(ostream &os, T &t);
private:
int a;
};
ostream& operator<<(ostream &os,T &t)
{
os<<t.a;
return os;
}
optional<string> fun1(bool b)
{
// return b? "hello":nullopt; // : liangbian bixuyao leixing yizhi ,qianzhe shi const char* houzhe bushi
if(b)
return "hello";
else
return {};
}
auto fun2(bool b)
{
return b? optional<string>("world"):nullopt;
}
auto fun3(bool b,optional<string> c)
{
return b? optional<reference_wrapper<string>>(c.value()):nullopt;
}
int main()
{
cout<<fun1(false).value_or("????")<<endl; //value_or(...)为返回optional的值,如果没有返回...
auto mv1 = fun2(true);
auto mv2 = fun3(true,mv1.value());
cout<<mv2->get()<<endl; // world
mv2->get() = "is";
cout<<mv2->get()<<endl; // is
auto opt = make_optional<vector<T>>(3,1); // make_optional使用
optional<vector<T>> opt1(in_place,vector<T>{4,3});// 这里与vector的emplace_back实质一致,可以穿args也可以传Tp的对象,如果是args,则在插入点构造,如果是传构造好的对象,则要move
optional<T> optt1(in_place,T(4)); //这里看下面log,打印出了the value is 4与this is move,说明先构造再move
optional<vector<T>> opt2(in_place,4,3); //使用in_place为了取代emplace,即在插入点构造,与上面少了move
cout << opt2.value().size() << endl; //4
opt2.emplace(3,4); //emplace用法,在插入点构造,同时会取代原来的值
cout << opt2.value().size() << endl; //3
for(auto a:*opt2){cout<<a<<endl;} //*opt2,为解引用
opt2.reset(); //若 *this 含值,则如同用 value().T::~T() 销毁此值。否则无效果
if(!opt2.has_value()) //has_value为判断是否有值
cout<<"std::bad_optional_access"<<endl;
}
????
world
is
the value is 1
the value is 4
the value is 3
the value is 4
this is move
the value is 3
4
the value is 4
3
4
4
4
std::bad_optional_access
cpp reference_std::variant
类模板 std::variant 表示一个类型安全的联合体。 std::variant 的一个实例在任意时刻要么保有其一个可选类型之一的值,要么在错误情况下无值(此状态难以达成,见 valueless_by_exception )。
其主要的用法如下所示
#include
#include
#include
#include
#include
#include
#include
using namespace std;
class T
{
public:
T(int i):a(i){cout<<"the value is "<<i<<endl;}
T(T&& t){this->a = t.a;cout<<"this is move"<<endl;}
T(const T& t)=default;
friend ostream& operator<<(ostream &os, T &t);
private:
int a;
};
ostream& operator<<(ostream &os,T &t)
{
os<<t.a;
return os;
}
int main()
{
variant<int,T,float> var1;
var1 = 1.2f; //直接用=初始化
cout<<"the variant is "<<get<float>(var1)<<endl; // 1.2
try {
get<int>(var1); // var1 含 float 而非 int :将抛出
}
catch (const std::bad_variant_access&) {}
//cout<<"the variant is "<(var1)<
var1 = 2;
cout<<"the variant is "<<get<int>(var1)<<endl; //2
cout<<"the variant is "<<get<0>(var1)<<endl; // get<0>(...) == get(...)
variant<int,T,float> var2(in_place_type<T>,3);
cout<<"the variant is "<<get<T>(var2)<<endl; //std::get<>()
variant<int,T,float> var3(in_place_type<T>,T(4)); //move
cout<<"the variant is "<<get<1>(var3)<<endl;
var3.emplace<2>(1.2f);
var3.emplace<1>(2); //这里注意与optional的emplace的区别,需要加定位
cout<<"the variant is "<<get<1>(var3)<<endl; // 2
cout<<var3.index()<<endl; // index == 1
using var_t = std::variant<int, long, double, std::string>;
std::vector<var_t> vec = {10, 15l, 1.5, "hello"};
for(auto v:vec){
visit([](auto&& args){std::cout << args<<endl;},v);
visit([](auto&& args){
using m_type = decay_t<decltype(args)>; //remove cv
if constexpr (is_same_v<m_type,int>){cout<<"the variant value is "<<args<<endl;} //if后跟constexpr为编译时判断
else if constexpr (is_same_v<m_type,long>){cout<<"the variant value is "<<args<<endl;}
else if constexpr (is_same_v<m_type,double>){cout<<"the variant value is "<<args<<endl;}
else if constexpr (is_same_v<m_type,string>){cout<<"the variant value is "<<args<<endl;}
},v);
}
}
the variant is 1.2
the variant is 2
the variant is 2
the value is 3
the variant is 3
the value is 4
this is move
the variant is 4
the value is 2
the variant is 2
1
10
the variant value is 10
15
the variant value is 15
1.5
the variant value is 1.5
hello
the variant value is hello
这里需要注意的是std::visit,配合variant来使用,前者输入为仿函数或者lambda,后者为variant,实现函数对variant的处理
template <class Visitor, class... Variants>
constexpr /*see below*/ visit(Visitor&& vis, Variants&&... vars);
(1) (C++17 起)
template <class R, class Visitor, class... Variants>
constexpr R visit(Visitor&& vis, Variants&&... vars);
#include
#include
#include
struct MyVisitor
{
void operator()(double d) const {
std::cout << d << '\n';
}
void operator()(int i) const {
std::cout << i << '\n';
}
void operator()(const std::string& s) const {
std::cout << s << '\n';
}
};
int main()
{
std::variant<int, double, std::string> var1(42), var2(3.14), var3("visit");
std::visit(MyVisitor(), var1); // calls operator() for matching int type
std::visit([](auto&& a){std::cout<<a<<std::endl;}, var3);
return 0;
}
42
visit
cpp_reference_std::any
类 any 描述用于任何类型的单个值的类型安全容器。
#include
#include
#include
using namespace std;
class T
{
public:
T(int i):a(i){cout<<"the value is "<<i<<endl;}
T(T&& t){this->a = t.a;cout<<"this is move"<<endl;}
T(const T& t)=default;
friend ostream& operator<<(ostream &os, T &t);
private:
int a;
};
int main()
{
std::any a = 1; //any赋值,然后需要使用时,再any_cast,之前需要判断是否has_value
cout<<a.has_value()<<endl; // true
cout<<a.type().name()<<" : "<<any_cast<int>(a)<<endl;
try
{
a = 1;
std::cout << std::any_cast<float>(a) << '\n';
}
catch (const std::bad_any_cast& e)
{
std::cout << e.what() << '\n';
}
auto b = make_any<T>(123);
cout<<b.type().name()<<endl; //1T
b.reset();
b.emplace<T>(234);
a = 1;
int* i = std::any_cast<int>(&a);// any_cast(指针)实现指针的类型转换,只能转换any值
std::cout << *i << "\n";
return 0;
}
1
i : 1
bad any_cast
the value is 123
1T
the value is 234
1