如果我有一个类,其数据的类型可以是int,float,double,char[],std::string,std::vector...现在我使用的是enum指示哪些类型的数据和void*动态的数据分配内存.但是,我确信必须有一个更优雅的方式.如何实现它而不使用boost?
实现"Variant"或"Any"类型,正如其他人指出的那样,您可以使用一些实现.但是如果你不想使用boost或其他替代品,你可以实现自己的简单版本.
您将需要2个类型的结构,一个将存储的基类,以及一个将保存实际对象的派生模板类.
让我们称之为占位符和持有者:
这是基础结构:
/**
* @brief The place holder structure..
*/
struct PlaceHolder
{
/**
* @brief Finalizes and instance of the PlaceHolder class.
*/
virtual ~PlaceHolder() {}
/**
* @brief Gets the type of the underlying value.
*/
virtual const std::type_info& getType() const = 0;
/**
* @brief Clones the holder.
*/
virtual PlaceHolder * clone() const = 0;
};
Run Code Online (Sandbox Code Playgroud)
这将是派生类:
template<typename ValueType>
struct Holder: public PlaceHolder
{
/**
* @brief Initializes a new instance of the Holder class.
*
* @param ValueType The value to be holded.
*/
Holder(const ValueType & value) : held(value) {}
/**
* @brief Gets the type of the underlying value.
*/
virtual const std::type_info & getType() const
{
return typeid(ValueType);
}
/**
* @brief Clones the holder.
*/
virtual PlaceHolder * clone() const
{
return new Holder(held);
}
ValueType held;
};
Run Code Online (Sandbox Code Playgroud)
现在我们可以这样:
PlaceHolder* any = new Holder<int>(3);
Run Code Online (Sandbox Code Playgroud)
我们可以像这样从中获取价值:
int number = static_cast<Holder<int> *>(any)->held;
Run Code Online (Sandbox Code Playgroud)
这不是很实用,所以我们创建了一个类来处理所有这些东西,并添加一些comodities,让我们称之为Any:
/**
* @brief This data type can be used to represent any other data type (for example, integer, floating-point,
* single- and double-precision, user defined types, etc.).
*
* While the use of not explicitly declared variants such as this is not recommended, they can be of use when the needed
* data type can only be known at runtime, when the data type is expected to vary, or when optional parameters
* and parameter arrays are desired.
*/
class Any
{
public:
/**
* @brief Initializes a new instance of the Any class.
*/
Any()
: m_content(0)
{
}
/**
* @brief Initializes a new instance of the Any class.
*
* @param value The value to be holded.
*/
template<typename ValueType>
Any(const ValueType & value)
: m_content(new Holder<ValueType>(value))
{
}
/**
* @brief Initializes a new instance of the Any class.
*
* @param other The Any object to copy.
*/
Any(const Any & other)
: m_content(other.m_content ? other.m_content->clone() : 0)
{
}
/**
* @brief Finalizes and instance of the Any class.
*/
virtual ~Any()
{
delete m_content;
}
/**
* @brief Exchange values of two objects.
*
* @param rhs The Any object to be swapped with.
*
* @return A reference to this.
*/
Any& swap(Any & rhs)
{
std::swap(m_content, rhs.m_content);
return *this;
}
/**
* @brief The assignment operator.
*
* @param rhs The value to be assigned.
*
* @return A reference to this.
*/
template<typename ValueType>
Any& operator=(const ValueType & rhs)
{
Any(rhs).swap(*this);
return *this;
}
/**
* @brief The assignment operator.
*
* @param rhs The value to be assigned.
*
* @return A reference to this.
*/
Any & operator=(const Any & rhs)
{
Any(rhs).swap(*this);
return *this;
}
/**
* @brief The () operator.
*
* @return The holded value.
*/
template<typename ValueType>
ValueType operator()() const
{
if (!m_content)
{
//TODO: throw
}
else if (getType() == typeid(ValueType))
{
return static_cast<Any::Holder<ValueType> *>(m_content)->held;
}
else
{
//TODO: throw
}
}
/**
* @brief Gets the underlying value.
*
* @return The holded value.
*/
template<typename ValueType>
ValueType get(void) const
{
if (!m_content)
{
//TODO: throw
}
else if (getType() == typeid(ValueType))
{
return static_cast<Any::Holder<ValueType> *>(m_content)->held;
}
else
{
//TODO: throw
}
}
/**
* @brief Tells whether the holder is empty or not.
*
* @return <tt>true</tt> if the holder is empty; otherwise <tt>false</tt>.
*/
bool isEmpty() const;
{
return !m_content;
}
/**
* @brief Gets the type of the underlying value.
*/
const std::type_info& getType() const;
{
return m_content ? m_content->getType() : typeid(void);
}
protected:
/**
* @brief The place holder structure..
*/
struct PlaceHolder
{
/**
* @brief Finalizes and instance of the PlaceHolder class.
*/
virtual ~PlaceHolder() {}
/**
* @brief Gets the type of the underlying value.
*/
virtual const std::type_info& getType() const = 0;
/**
* @brief Clones the holder.
*/
virtual PlaceHolder * clone() const = 0;
};
template<typename ValueType>
struct Holder: public PlaceHolder
{
/**
* @brief Initializes a new instance of the Holder class.
*
* @param ValueType The value to be holded.
*/
Holder(const ValueType & value) : held(value) {}
/**
* @brief Gets the type of the underlying value.
*/
virtual const std::type_info & getType() const
{
return typeid(ValueType);
}
/**
* @brief Clones the holder.
*/
virtual PlaceHolder * clone() const
{
return new Holder(held);
}
ValueType held;
};
protected:
PlaceHolder* m_content;
};
Run Code Online (Sandbox Code Playgroud)
此实现基于Any of Ogre
你可以使用它,例如:
int main()
{
Any three = 3;
int number = three.get<int>();
cout << number << "\n";
three = string("Three");
std::string word = three.get<string>();
cout << word << "\n";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
3
Three
Run Code Online (Sandbox Code Playgroud)