#std::any
C++17から登場したstd::anyはどんな型の値でもつっこめる型です
main.cpp
#include<iostream>
#include<string>
#include<any>
template<class Type>
void Println(std::any& _any)
{
if (auto& type = _any.type(); type == typeid(Type))
{
std::cout << std::any_cast<Type>(_any) << std::endl;
}
else
{
std::cout << "can't any_cast" << std::endl;
}
}
int main()
{
std::any a;
a = 2;
Println<int>(a);
a = 1.14;
Println<double>(a);
a = std::string("hellow");
Println<std::string>(a);
return 0;
}
#参照として代入するには
main.cpp
int main()
{
int hoge = 0;
std::any a = hoge;
std::any_cast<int&>(a)++;
std::cout << hoge <<std::endl;
return 0;
}
このようなコードを書いても当然hoge
の値は0
のままとなります
では、hoge
も書き換えたい場合どうすればよいのか
##ポインタにしてみる
main.cpp
int main()
{
int hoge = 0;
std::any a=&hoge;
(*std::any_cast<int*>(a))++;
std::cout << hoge<<std::endl;
return 0;
}
タイトルと話がずれますがアドレスを渡してポインタにしてしまうのも一つの手です。
この場合hoge
も1
になります
##std::refを使ってみる
main.cpp
int main()
{
int hoge = 0;
//参照
std::any a=std::ref(hoge);
std::any_cast<std::reference_wrapper<int>>(a)++;
std::cout << hoge<<std::endl;
//const参照
a = std::cref(hoge);
std::cout << std::any_cast<std::reference_wrapper<const int>>(a) << std::endl;
return 0;
}
この方法でもhoge
の値を書き換えることが可能です。
しかしany_castでstd::reference_wrapper
にしないとうまくキャストできません、気持ち的には<int&>
や<const int&>
で扱いたいです。
###any_castをラップする
上のような問題を解決するためにany_castをラップした関数を作ります。
namespace detail
{
//実装
template<class T>
struct AnyCastImpl
{
static T Func(std::any& _any)
{
using Type = std::remove_const_t<T>;
if (auto& type = _any.type(); type == typeid(std::reference_wrapper<Type>))
{
return std::any_cast<std::reference_wrapper<Type>>(_any);
}
else if (type == typeid(std::reference_wrapper<const Type>))
{
return std::any_cast<std::reference_wrapper<const Type>>(_any);
}
return std::any_cast<T>(_any);
}
};
//参照
template<class T>
struct AnyCastImpl<T&>
{
static T& Func(std::any& _any)
{
if (_any.type() == typeid(std::reference_wrapper<T>))
{
return std::any_cast<std::reference_wrapper<T>>(_any);
}
return std::any_cast<T&>(_any);
}
};
//const参照
template<class T>
struct AnyCastImpl<const T&>
{
static const T& Func(std::any& _any)
{
if (auto& type = _any.type(); type == typeid(std::reference_wrapper<T>))
{
return std::any_cast<std::reference_wrapper<T>>(_any);
}
else if (type == typeid(std::reference_wrapper<const T>))
{
return std::any_cast<std::reference_wrapper<const T>>(_any);
}
return std::any_cast<T&>(_any);
}
};
}
//ラップ関数
template<class T>
T any_cast_wrapper(std::any& _any)
{
return detail::AnyCastImpl<T>::Func(_any);
}
std::reference_wrapper<const T>
→T&
の変換は不可なので特殊化しておく
使い方は下のような感じ
main.cpp
int main()
{
int hoge = 0;
//参照
std::any a=std::ref(hoge);
any_cast_wrapper<int&>(a)++; //参照
any_cast_wrapper<const int&>(a); //const参照
int b=any_cast_wrapper<int>(a); //コピー
std::cout << hoge<<std::endl;
//const参照
a = std::cref(hoge);
try
{
any_cast_wrapper<int&>(a)++; //参照への変換はbad_any_cast例外
}
catch (std::bad_any_cast e)
{
std::cout << e.what() << std::endl;
}
any_cast_wrapper<const int&>(a); //const参照
b = any_cast_wrapper<int>(a); //コピー
return 0;
}
#まとめ
anyに参照として代入したい場合は、諦めてアドレスを渡すか、std::refをうまく使う