我将包含异构模板值的模板化类的实例放入容器中,例如std :: vector。当从所述向量访问特定元素时,我要求返回精确模板化类型,而不仅仅是基指针WrapperBase*
。我已经涉及了boost :: any,boost :: variant和基类/模板化的子类,如下所示。编译时解决方案是理想的(也许是一些元模板魔法);否则,基于运行时RTTI的解决方案就足够了。
在一个完美的世界里,我可以做这样的事情:
vector< WrapperBase > v;
v.push_back( Wrapper<int>{1} );
v.push_back( Wrapper<float>{3.14f} );
auto v = vector[0].get(); //typeid( decltype( v) ).name() would be "int"
auto v = vector[1].get(); //typeid( decltype( v) ).name() would be "float"
Boost变体几乎提供了解决方案;但是,我只能访问operator()()
方法中的特定类型,并且无法返回它。该类型将被其他函数使用,因此我无法使访问者方法执行所需的工作。
此代码可用http://coliru.stacked-crooked.com/a/5a44681322cdbd77
#include <iostream>
#include <type_traits>
#include <vector>
#include <boost/variant.hpp>
#include <boost/any.hpp>
struct WrapperBase
{
template< typename T >
T* get();
};
template< typename T >
struct Wrapper : WrapperBase
{
Wrapper( T* t ) : WrapperBase(), _val( t ) {}
T* get() { return _val; }
T* _val;
};
template< typename T >
T* WrapperBase::get()
{
return static_cast<Wrapper<T>>( this )->get();
}
struct Visitor : boost::static_visitor<int> //sadly, we can only return ints :(.
{
int operator()( Wrapper<int>& b ) const
{
auto bType = *b.get();
std::cout << "b type is " << typeid( decltype( bType ) ).name() << "... Val is " << bType << "...\n";
return 2;
}
int operator()( Wrapper<float>& b ) const
{
auto bType = *b.get();
std::cout << "b type is " << typeid( decltype( bType ) ).name() << "... Val is " << bType << "...\n";
return 6;
}
int operator()( Wrapper<std::string>& b ) const
{
auto bType = *b.get();
std::cout << "b type is " << typeid( decltype( bType ) ).name() << "... Val is " << bType << "...\n";
return 12345;
}
};
int main( int argc, char* args[] )
{
std::cout << "Hello World...\n";
int ia = 5;
Wrapper<int> a{ &ia };
float fb = 3.1415f;
Wrapper<float> b{ &fb };
std::string s = "testing this...\n";
Wrapper<std::string> c{ &s };
auto aType = *a.get(); //aType is "int"
std::cout << "a type is " << typeid( decltype( aType ) ).name() << "... Val is " << aType << "...\n";
auto bType = *b.get(); //aType is "float"
std::cout << "b type is " << typeid( decltype( bType ) ).name() << "... Val is " << bType << "...\n";
auto cType = *c.get(); //aType is "std::string"
std::cout << "c type is " << typeid( decltype( cType ) ).name() << "... Val is " << cType << "...\n";
std::vector< boost::any > vec;
vec.push_back( &a );
vec.push_back( &b );
vec.push_back( &c );
//for( int i = 0; i < vec.size() ; i++ )
//{
//In my actual code, I have no way of knowing I need to cast to <int> and therefore cannot cast.
// auto t = boost::any_cast<Wrapper<int>*>( vec[i] );
// std::cout << "[" << i << "] type is " << typeid( decltype( t ) ).name() << "... Val is " << t << "...\n";
//}
std::cout << "...\n...\n...\n";
using VAR = boost::variant< Wrapper<int>, Wrapper<float>, Wrapper<std::string> >;
std::vector< VAR > myVar;
myVar.push_back( a );
myVar.push_back( b );
myVar.push_back( c );
for (int i = 0; i < myVar.size() ; i++)
{
auto v = myVar[i];
//apply_visitor is VERY close to what I want - I have precise type, but only within operator()()
std::cout << boost::apply_visitor( Visitor(), v ) << "\n";
}
std::cout << "...\n...\n...\n";
std::vector< WrapperBase > v;
v.push_back( a );
v.push_back( b );
v.push_back( c );
//for (int i = 0; i < v.size() ; i++)
//{
// auto t = v[i].get<int>(); //same problem as boost::any, but instead I have pointer to base class
// std::cout << "["<<i<<"] type is " << typeid( decltype( t )).name() << "... Val is " << t << "...\n";
//
//}
return 0;
}
答案 0 :(得分:2)
这篇精彩的文章讨论了如何将访问者模式与类型删除的基础对象(如std::any
https://gieseanw.wordpress.com/2017/05/03/a-true-heterogeneous-container-in-c/一起使用,所以如果你使用那里的概念,你可以在理论上使用访客模式与同质容器。
您获取此类代码的目标
// typeid(val_one).name() is
auto val_one = homogenous_container[runtime_value_one];
// typeid(val_two).name() is `double`
auto val_two = homogenous_container[runtime_value_two];
无法实现,auto
类型推导在编译时发生,没有办法让它绑定到运行时条件并根据它改变类型。
您最接近的是使用std::variant
并使用访客模式。您不能将编译时推断类型绑定到任意运行时类型。它们只是不同的概念,并且在C ++编译/运行时的不同时间存在。
类型擦除将允许您实现这样的一些功能,但它要求您的容器由共享一些公共接口的类型组成。例如,在std::function
的情况下,可以根据std::function