std::any和枚举类转换

一、std::any和enum class

在前面分析过std::any和enum class的初步应用,但是在实际应用 中,这两个之间在一起应用时还是要有些小细节需要注意。在程序的开发中,一般来说,不建议直接使用魔数来进行各种情况下的区别。毕竟时间长久后,这些魔数会变得不好理解甚至误解。同样,枚举类的出现导致直接使用枚举的不安全行为得到了控制,但也相应的出现了数据转换的问题。
对于std::any也是如此,它既然可以存储各种数据类型,就会有各种不同的情况出现。如果两者在一起使用,会出现一些具体的问题需要说明一下。

二、应用分析

1、枚举类的直接转换
枚举类和普通值的互转用得还是比较多的:

enum class K:int { k1 = 1, k2 };

int a = 10;
K k = k(a);

a = static_cast<int>(k);

这个还是比较简单的。
看一个稍微复杂的:

	#include 
	#include 
	 
	enum e1 {};
	enum class e2 {};
	enum class e3: unsigned {};
	enum class e4: int {};
	 
	int main() {
	 
	  constexpr bool e1_t = std::is_same_v< std::underlying_type_t, int >;
	  constexpr bool e2_t = std::is_same_v< std::underlying_type_t, int >;
	  constexpr bool e3_t = std::is_same_v< std::underlying_type_t, int >;
	  constexpr bool e4_t = std::is_same_v< std::underlying_type_t, int >;
	 
	  std::cout
	    << "underlying type for 'e1' is " << (e1_t ? "int" : "non-int") << '\n'
	    << "underlying type for 'e2' is " << (e2_t ? "int" : "non-int") << '\n'
	    << "underlying type for 'e3' is " << (e3_t ? "int" : "non-int") << '\n'
	    << "underlying type for 'e4' is " << (e4_t ? "int" : "non-int") << '\n'
	    ;
	}

可能输出:

underlying type for 'e1' is non-int
underlying type for 'e2' is int
underlying type for 'e3' is non-int
underlying type for 'e4' is int

2、std::any的处理
一般来说把对象转成std::any直接赋值即可,而反之则需要使用std::any_cast():

std::any x = 10;
int v = std::any<int>(x);

3、枚举类通用转化
在上面的代码中对枚举进行了转换,将普通值转成枚举类还好说一些,直接调用构造函数即可,但反过来则比较麻烦,可以有一个比较通用的方式:

// print enum class
enum class K { k1 = 1, k2 };

enum class T { t1, t2 };
template <typename T> auto print(T const v) -> typename std::underlying_type<T>::type {
  return static_cast<typename std::underlying_type<T>::type>(v);
}

void printEnumClass() {
  auto k = K::k1;
  auto t = T::t2;
  std::cout << print(k) << std::endl;
  std::cout << print(t) << std::endl;
}

这里使用了std::underlying_type,不过不使用其也可以,直接用static_cast,就看各自的习惯了。

4、std::in_place_type的应用
std::underlying_type有几个相类似的函数,可以应用在std::optional和std::variant和std::any中,这里只是分析一下在std::any中的应用。先看一个例子:

#include 
#include 
void test_inplace() {

  //first
  std::any a = 6;
  a = std::any{std::in_place_type<std::string>, "test"};

  std::any ab{std::in_place_type<long long>, 1};

  //second
  std::any com{std::complex{1.0, 3.0}};
  std::any com_d{std::in_place_type<std::complex<double>>, 2.0, 4.6};

  //third
  auto ret = [](int a, int b) { return true; };
  std::any any_ret{std::in_place_type<std::set<int, decltype(ret)>>, {3, 9}, ret};
}
int main()
{
  test_inplace();
  return 0;
}

简单的应用就不用介绍了,很容易就明白。上面的代码有几个应用 的不同方式,第一个是如果std::any在已经赋值其它类型后想再给予另外一种类型,就必须使用std::in_place_type来处理,比如上面代码的第一种;而第二种是对处理多个对象参数初始化的情况,也需要使用其来实现;第三种是可以使用std::in_place_type来实现初始化列表,在其后面跟上参数即可。
如果不想使用std::in_place_type,其它它还有一个更方便的函数make_any<>(),这个看来成为了标准库里处理的一个通行方法,一律make_xx一下,问题就解决了。另外,使用std::in_place_type,仍然会出现类似指针退化(数组转化成指针)的情况,这个需要注意。
5、两者共同使用
下面只给一个简单的例子就明白了。

 int preStatus = static_cast<int>(std::any_cast<K>(k));

三、总结

有些细节在应用开发时,可能还会费一些精神。其实重点不是这些细节多难,而是有时候儿遇到之时才会认真去追究这些细节的实现。实践出真知,诚不我欺。

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