Now type_index class can store cvr modifiers too.

This commit is contained in:
Antony Polukhin
2013-10-16 16:43:32 +04:00
parent c7020e6ecd
commit ecb9839e04
6 changed files with 168 additions and 4 deletions

View File

@@ -213,6 +213,8 @@ template_index template_id() BOOST_NOEXCEPT {
/// Factory method for constructing template_index instance for type T.
/// Does not strips const, volatile and & modifiers from T.
/// If T has no const, volatile, & and && modifiers, then returns exactly
/// the same result as in case of calling `template_id<T>()`.
template <class T>
template_index template_id_with_cvr() BOOST_NOEXCEPT {
return template_index::construct_with_cvr<T>();

View File

@@ -26,8 +26,12 @@
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_arithmetic.hpp>
#include <boost/type_traits/is_const.hpp>
#include <boost/type_traits/is_reference.hpp>
#include <boost/type_traits/is_volatile.hpp>
#include <boost/type_traits/remove_cv.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/mpl/if.hpp>
#include <boost/current_function.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/functional/hash_fwd.hpp>
@@ -67,6 +71,10 @@ namespace boost {
#endif // BOOST_TYPE_INDEX_DOXYGEN_INVOKED
namespace detail {
template <class T> class cvr_saver{};
}
/// Copyable type_info class that requires RTTI.
class type_index {
public:
@@ -107,6 +115,22 @@ public:
return type_index(typeid(no_cvr_t));
}
/// Factory method for constructing type_index instance for type T.
/// Does not strips const, volatile, & and && modifiers from T.
/// If T has no const, volatile, & and && modifiers, then returns exactly
/// the same result as in case of calling `construct<T>()`.
template <class T>
static type_index construct_with_cvr() BOOST_NOEXCEPT {
typedef typename boost::mpl::if_c<
boost::is_reference<T>::value
|| boost::is_const<T>::value
|| boost::is_volatile<T>::value,
detail::cvr_saver<T>,
T
>::type type;
return construct<type>();
}
/// Factory function, that works exactly like C++ typeid(rtti_val) call, but returns boost::type_index.
/// This method available only with RTTI enabled.
template <class T>
@@ -140,7 +164,7 @@ public:
std::string name_demangled() const {
#if defined(__GNUC__)
std::string ret;
int status = 0 ;
int status = 0;
char* demang = abi::__cxa_demangle(pinfo_->name(), NULL, 0, &status);
BOOST_ASSERT(!status);
@@ -152,10 +176,26 @@ public:
} BOOST_CATCH_END
free(demang);
return ret;
#else
return pinfo_->name();
std::string ret = pinfo_->name();
#endif
std::string::size_type pos = ret.find("boost::detail::cvr_saver<");
if (pos == std::string::npos) {
return ret;
}
pos += sizeof("boost::detail::cvr_saver<");
while (ret[pos] == ' ') {
++ pos;
}
std::string::size_type end = ret.rfind(">");
BOOST_ASSERT(end != std::string::npos);
-- end;
while (ret[end] == ' ') {
-- end;
}
return ret.substr(pos, end - pos);
}
#ifndef BOOST_TYPE_INDEX_DOXYGEN_INVOKED
@@ -280,6 +320,15 @@ type_index type_id() BOOST_NOEXCEPT {
return type_index::construct<T>();
}
/// Function for constructing type_index instance for type T.
/// Does not strips const, volatile, & and && modifiers from T.
/// If T has no const, volatile, & and && modifiers, then returns exactly
/// the same result as in case of calling `type_id<T>()`.
template <class T>
type_index type_id_with_cvr() BOOST_NOEXCEPT {
return type_index::construct_with_cvr<T>();
}
/// Function, that works exactly like C++ typeid(rtti_val) call, but returns boost::type_index.
/// This method available only with RTTI enabled.
template <class T>

View File

@@ -34,6 +34,11 @@ type_index type_id() {
return template_index::construct<T>();
}
template <class T>
type_index type_id_with_cvr() {
return template_index::construct_with_cvr<T>();
}
} // namespace boost
#endif // BOOST_NO_RTTI

View File

@@ -10,7 +10,7 @@
Example works with and without RTTI.
In this example we'll create a class, that stores pointer to function and remembers the exact type of a parameter that function accepts.
When an attempt to call the stored function will be made, type of input parameter will be checked for exact match with initail/erased type of function.
When an attempt to call the stored function will be made, type of input parameter will be checked for exact match with initaily erased type of function.
*/
#include <boost/type_index.hpp>

View File

@@ -109,6 +109,32 @@ BOOST_AUTO_TEST_CASE(template_id_storing_modifiers)
test_with_modofiers<int&, const volatile int&>();
}
template <class T>
static void test_storing_nonstoring_modifiers_templ() {
using namespace boost;
template_index t1 = template_id_with_cvr<T>();
template_index t2 = template_id<T>();
BOOST_CHECK_EQUAL(t2, t1);
BOOST_CHECK_EQUAL(t1, t2);
BOOST_CHECK(t1 <= t2);
BOOST_CHECK(t1 >= t2);
BOOST_CHECK(t2 <= t1);
BOOST_CHECK(t2 >= t1);
}
BOOST_AUTO_TEST_CASE(template_id_storing_modifiers_vs_nonstoring)
{
test_storing_nonstoring_modifiers_templ<int>();
test_storing_nonstoring_modifiers_templ<my_namespace1::my_class>();
test_storing_nonstoring_modifiers_templ<my_namespace2::my_class>();
boost::template_index t1 = boost::template_id_with_cvr<const int>();
boost::template_index t2 = boost::template_id<int>();
BOOST_CHECK_NE(t2, t1);
}
BOOST_AUTO_TEST_CASE(template_index_stream_operator_via_lexical_cast_testing)
{
using namespace boost;

View File

@@ -103,6 +103,88 @@ BOOST_AUTO_TEST_CASE(comparators_type_id_vs_type_info)
#endif // BOOST_NO_RTTI
template <class T1, class T2>
static void test_with_modofiers_type_id() {
using namespace boost;
type_index t1 = type_id_with_cvr<T1>();
type_index t2 = type_id_with_cvr<T2>();
BOOST_CHECK_NE(t2, t1);
BOOST_CHECK(t1 < t2 || t2 < t1);
BOOST_CHECK(t1 > t2 || t2 > t1);
BOOST_CHECK_EQUAL(t1, type_id_with_cvr<T1>());
BOOST_CHECK_EQUAL(t2, type_id_with_cvr<T2>());
BOOST_CHECK_EQUAL(t1.hash_code(), type_id_with_cvr<T1>().hash_code());
BOOST_CHECK_EQUAL(t2.hash_code(), type_id_with_cvr<T2>().hash_code());
BOOST_CHECK_NE(t1.hash_code(), type_id_with_cvr<T2>().hash_code());
BOOST_CHECK_NE(t2.hash_code(), type_id_with_cvr<T1>().hash_code());
}
BOOST_AUTO_TEST_CASE(type_id_storing_modifiers)
{
test_with_modofiers_type_id<int, const int>();
test_with_modofiers_type_id<int, const int&>();
test_with_modofiers_type_id<int, int&>();
test_with_modofiers_type_id<int, volatile int>();
test_with_modofiers_type_id<int, volatile int&>();
test_with_modofiers_type_id<int, const volatile int>();
test_with_modofiers_type_id<int, const volatile int&>();
test_with_modofiers_type_id<const int, int>();
test_with_modofiers_type_id<const int, const int&>();
test_with_modofiers_type_id<const int, int&>();
test_with_modofiers_type_id<const int, volatile int>();
test_with_modofiers_type_id<const int, volatile int&>();
test_with_modofiers_type_id<const int, const volatile int>();
test_with_modofiers_type_id<const int, const volatile int&>();
test_with_modofiers_type_id<const int&, int>();
test_with_modofiers_type_id<const int&, const int>();
test_with_modofiers_type_id<const int&, int&>();
test_with_modofiers_type_id<const int&, volatile int>();
test_with_modofiers_type_id<const int&, volatile int&>();
test_with_modofiers_type_id<const int&, const volatile int>();
test_with_modofiers_type_id<const int&, const volatile int&>();
test_with_modofiers_type_id<int&, const int>();
test_with_modofiers_type_id<int&, const int&>();
test_with_modofiers_type_id<int&, int>();
test_with_modofiers_type_id<int&, volatile int>();
test_with_modofiers_type_id<int&, volatile int&>();
test_with_modofiers_type_id<int&, const volatile int>();
test_with_modofiers_type_id<int&, const volatile int&>();
}
template <class T>
static void test_storing_nonstoring_modifiers() {
using namespace boost;
type_index t1 = type_id_with_cvr<T>();
type_index t2 = type_id<T>();
BOOST_CHECK_EQUAL(t2, t1);
BOOST_CHECK_EQUAL(t1, t2);
BOOST_CHECK(t1 <= t2);
BOOST_CHECK(t1 >= t2);
BOOST_CHECK(t2 <= t1);
BOOST_CHECK(t2 >= t1);
}
BOOST_AUTO_TEST_CASE(type_id_storing_modifiers_vs_nonstoring)
{
test_storing_nonstoring_modifiers<int>();
test_storing_nonstoring_modifiers<my_namespace1::my_class>();
test_storing_nonstoring_modifiers<my_namespace2::my_class>();
boost::type_index t1 = boost::type_id_with_cvr<const int>();
boost::type_index t2 = boost::type_id<int>();
BOOST_CHECK_NE(t2, t1);
}
BOOST_AUTO_TEST_CASE(type_index_stream_operator_via_lexical_cast_testing)
{
using namespace boost;