2014-06-01 17:55:23 +00:00
|
|
|
/*
|
|
|
|
* This file is part of the DXX-Rebirth project <http://www.dxx-rebirth.com/>.
|
|
|
|
* It is copyright by its individual contributors, as recorded in the
|
|
|
|
* project's Git history. See COPYING.txt at the top level for license
|
|
|
|
* terms and a link to the Git history.
|
|
|
|
*/
|
2013-12-24 04:53:59 +00:00
|
|
|
#pragma once
|
2014-07-05 22:00:08 +00:00
|
|
|
|
|
|
|
#include <stdexcept>
|
2015-05-09 17:39:02 +00:00
|
|
|
#include <string>
|
2015-10-09 02:46:11 +00:00
|
|
|
#include "fwd-valptridx.h"
|
2015-09-09 03:27:52 +00:00
|
|
|
#include "compiler-array.h"
|
2015-07-09 03:12:45 +00:00
|
|
|
#include "compiler-static_assert.h"
|
2014-07-11 03:14:50 +00:00
|
|
|
#include "compiler-type_traits.h"
|
2014-12-14 05:23:00 +00:00
|
|
|
#include "pack.h"
|
2015-08-22 20:43:04 +00:00
|
|
|
#include "poison.h"
|
2014-07-11 03:14:50 +00:00
|
|
|
|
2015-08-22 20:43:04 +00:00
|
|
|
#ifdef DXX_CONSTANT_TRUE
|
2015-05-09 17:39:02 +00:00
|
|
|
#define DXX_VALPTRIDX_STATIC_CHECK(SUCCESS_CONDITION,FAILURE_FUNCTION,FAILURE_STRING) \
|
|
|
|
( \
|
2015-08-22 20:43:04 +00:00
|
|
|
static_cast<void>(DXX_CONSTANT_TRUE(!(SUCCESS_CONDITION)) && \
|
2015-05-09 17:39:02 +00:00
|
|
|
(DXX_ALWAYS_ERROR_FUNCTION(FAILURE_FUNCTION, FAILURE_STRING), 0) \
|
|
|
|
) \
|
|
|
|
)
|
2015-09-26 21:17:12 +00:00
|
|
|
|
|
|
|
#ifdef DXX_HAVE_ATTRIBUTE_WARNING
|
|
|
|
/* This causes many warnings because some conversions are not checked for
|
|
|
|
* safety. Eliminating the warnings by changing the call sites to check first
|
|
|
|
* would be a useful improvement.
|
|
|
|
*/
|
|
|
|
//#define DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT __attribute__((__warning__("call not eliminated")))
|
|
|
|
#endif
|
2014-07-11 03:14:50 +00:00
|
|
|
#else
|
2014-07-31 02:47:46 +00:00
|
|
|
#define DXX_VALPTRIDX_STATIC_CHECK(E,F,S) \
|
2014-08-09 17:38:45 +00:00
|
|
|
((void)0)
|
2014-07-11 03:14:50 +00:00
|
|
|
#endif
|
|
|
|
|
2014-09-13 22:01:17 +00:00
|
|
|
#ifdef DXX_HAVE_CXX11_REF_QUALIFIER
|
|
|
|
#define DXX_VALPTRIDX_REF_QUALIFIER_LVALUE &
|
|
|
|
#else
|
|
|
|
#define DXX_VALPTRIDX_REF_QUALIFIER_LVALUE
|
|
|
|
#endif
|
|
|
|
|
2015-05-09 17:39:02 +00:00
|
|
|
#define DXX_VALPTRIDX_CHECK(SUCCESS_CONDITION,EXCEPTION,FAILURE_STRING,...) \
|
2014-08-09 17:38:45 +00:00
|
|
|
( \
|
2015-05-09 17:39:02 +00:00
|
|
|
static_cast<void>(DXX_VALPTRIDX_STATIC_CHECK((SUCCESS_CONDITION), dxx_trap_##EXCEPTION, FAILURE_STRING), \
|
2015-07-09 03:12:45 +00:00
|
|
|
(SUCCESS_CONDITION) || (EXCEPTION::report(__VA_ARGS__), 0) \
|
2015-05-09 17:39:02 +00:00
|
|
|
) \
|
2014-08-09 17:38:45 +00:00
|
|
|
)
|
|
|
|
|
2015-09-26 21:17:12 +00:00
|
|
|
#ifndef DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
|
|
|
|
#define DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
|
|
|
|
#endif
|
|
|
|
|
2015-07-09 03:12:45 +00:00
|
|
|
template <typename P>
|
|
|
|
class valptridx<P>::index_mismatch_exception :
|
|
|
|
public std::logic_error
|
2013-12-24 04:53:59 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
DXX_INHERIT_CONSTRUCTORS(index_mismatch_exception, logic_error);
|
|
|
|
public:
|
2015-05-09 17:39:02 +00:00
|
|
|
__attribute_cold
|
|
|
|
__attribute_noreturn
|
2015-09-26 21:17:12 +00:00
|
|
|
DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
|
2015-10-13 02:43:24 +00:00
|
|
|
static void report(const array_managed_type &, index_type, const_pointer_type, const_pointer_type);
|
2015-07-09 03:12:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
template <typename P>
|
|
|
|
class valptridx<P>::index_range_exception :
|
|
|
|
public std::out_of_range
|
|
|
|
{
|
|
|
|
DXX_INHERIT_CONSTRUCTORS(index_range_exception, out_of_range);
|
|
|
|
public:
|
2015-05-09 17:39:02 +00:00
|
|
|
__attribute_cold
|
|
|
|
__attribute_noreturn
|
2015-09-26 21:17:12 +00:00
|
|
|
DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
|
2015-10-13 02:43:24 +00:00
|
|
|
static void report(const array_managed_type &, long);
|
2015-07-09 03:12:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
template <typename P>
|
|
|
|
class valptridx<P>::null_pointer_exception :
|
|
|
|
public std::logic_error
|
|
|
|
{
|
|
|
|
DXX_INHERIT_CONSTRUCTORS(null_pointer_exception, logic_error);
|
|
|
|
public:
|
2015-05-09 17:39:02 +00:00
|
|
|
__attribute_cold
|
|
|
|
__attribute_noreturn
|
2015-09-26 21:17:12 +00:00
|
|
|
DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
|
2015-10-13 02:43:24 +00:00
|
|
|
static void report();
|
|
|
|
__attribute_cold
|
|
|
|
__attribute_noreturn
|
|
|
|
DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
|
|
|
|
static void report(const array_managed_type &);
|
2014-09-12 03:22:34 +00:00
|
|
|
};
|
|
|
|
|
2015-07-09 03:12:45 +00:00
|
|
|
template <typename managed_type>
|
|
|
|
void valptridx<managed_type>::check_index_match(const managed_type &r, index_type i, const array_managed_type &a)
|
|
|
|
{
|
|
|
|
const auto pi = &a[i];
|
2015-10-13 02:43:24 +00:00
|
|
|
DXX_VALPTRIDX_CHECK(pi == &r, index_mismatch_exception, "pointer/index mismatch", a, i, pi, &r);
|
2015-07-09 03:12:45 +00:00
|
|
|
}
|
2014-09-12 03:22:34 +00:00
|
|
|
|
2015-07-09 03:12:45 +00:00
|
|
|
template <typename managed_type>
|
|
|
|
typename valptridx<managed_type>::index_type valptridx<managed_type>::check_index_range(index_type i, const array_managed_type &a)
|
|
|
|
{
|
|
|
|
const std::size_t ss = i;
|
2015-10-13 02:43:24 +00:00
|
|
|
DXX_VALPTRIDX_CHECK(ss < a.size(), index_range_exception, "invalid index used in array subscript", a, ss);
|
2015-07-09 03:12:45 +00:00
|
|
|
return i;
|
|
|
|
}
|
2014-09-12 03:22:34 +00:00
|
|
|
|
2015-08-22 20:43:04 +00:00
|
|
|
template <typename managed_type>
|
|
|
|
void valptridx<managed_type>::check_null_pointer_conversion(const_pointer_type p)
|
|
|
|
{
|
2015-10-13 02:43:24 +00:00
|
|
|
DXX_VALPTRIDX_CHECK(p, null_pointer_exception, "NULL pointer converted");
|
2015-08-22 20:43:04 +00:00
|
|
|
}
|
|
|
|
|
2015-07-09 03:12:45 +00:00
|
|
|
template <typename managed_type>
|
|
|
|
void valptridx<managed_type>::check_null_pointer(const_pointer_type p, const array_managed_type &a)
|
|
|
|
{
|
2015-10-13 02:43:24 +00:00
|
|
|
DXX_VALPTRIDX_CHECK(p, null_pointer_exception, "NULL pointer used", a);
|
2015-07-09 03:12:45 +00:00
|
|
|
}
|
2014-10-02 03:02:34 +00:00
|
|
|
|
2015-07-09 03:12:45 +00:00
|
|
|
template <typename managed_type>
|
|
|
|
void valptridx<managed_type>::check_implicit_index_range_ref(const managed_type &r, const array_managed_type &a)
|
|
|
|
{
|
2015-09-15 02:48:04 +00:00
|
|
|
check_explicit_index_range_ref(r, static_cast<const_pointer_type>(&r) - static_cast<const_pointer_type>(&a.front()), a);
|
2015-07-09 03:12:45 +00:00
|
|
|
}
|
2014-10-02 03:02:34 +00:00
|
|
|
|
2015-07-09 03:12:45 +00:00
|
|
|
template <typename managed_type>
|
|
|
|
void valptridx<managed_type>::check_explicit_index_range_ref(const managed_type &r, std::size_t i, const array_managed_type &a)
|
|
|
|
{
|
|
|
|
check_index_match(r, i, a);
|
|
|
|
check_index_range(i, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename managed_type>
|
|
|
|
class valptridx<managed_type>::partial_policy::require_valid
|
2014-09-12 03:22:34 +00:00
|
|
|
{
|
2014-12-02 04:36:19 +00:00
|
|
|
public:
|
2015-07-09 03:12:45 +00:00
|
|
|
static constexpr tt::false_type allow_nullptr{};
|
|
|
|
static constexpr tt::false_type check_allowed_invalid_index(index_type) { return {}; }
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename managed_type>
|
|
|
|
class valptridx<managed_type>::partial_policy::allow_invalid
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static constexpr tt::true_type allow_nullptr{};
|
|
|
|
static constexpr bool check_allowed_invalid_index(index_type i)
|
2014-09-12 03:22:34 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
return i == static_cast<index_type>(~0);
|
2014-09-12 03:22:34 +00:00
|
|
|
}
|
2015-07-09 03:12:45 +00:00
|
|
|
};
|
|
|
|
|
2015-07-25 23:10:46 +00:00
|
|
|
template <typename managed_type>
|
|
|
|
constexpr tt::false_type valptridx<managed_type>::partial_policy::require_valid::allow_nullptr;
|
|
|
|
|
|
|
|
template <typename managed_type>
|
|
|
|
constexpr tt::true_type valptridx<managed_type>::partial_policy::allow_invalid::allow_nullptr;
|
|
|
|
|
2015-07-09 03:12:45 +00:00
|
|
|
template <typename managed_type>
|
|
|
|
class valptridx<managed_type>::partial_policy::const_policy
|
|
|
|
{
|
2014-09-12 03:22:34 +00:00
|
|
|
protected:
|
2015-07-09 03:12:45 +00:00
|
|
|
template <typename T>
|
|
|
|
using apply_cv_qualifier = const T;
|
2014-09-12 03:22:34 +00:00
|
|
|
};
|
|
|
|
|
2015-07-09 03:12:45 +00:00
|
|
|
template <typename managed_type>
|
|
|
|
class valptridx<managed_type>::partial_policy::mutable_policy
|
2014-09-12 03:22:34 +00:00
|
|
|
{
|
|
|
|
protected:
|
2015-07-09 03:12:45 +00:00
|
|
|
template <typename T>
|
|
|
|
using apply_cv_qualifier = T;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename managed_type>
|
|
|
|
template <typename policy>
|
|
|
|
class valptridx<managed_type>::partial_policy::apply_cv_policy :
|
|
|
|
policy
|
|
|
|
{
|
|
|
|
template <typename T>
|
|
|
|
using apply_cv_qualifier = typename policy::template apply_cv_qualifier<T>;
|
2014-09-12 03:22:34 +00:00
|
|
|
public:
|
2015-07-09 03:12:45 +00:00
|
|
|
using array_managed_type = apply_cv_qualifier<valptridx<managed_type>::array_managed_type>;
|
|
|
|
using pointer_type = apply_cv_qualifier<managed_type> *;
|
|
|
|
using reference_type = apply_cv_qualifier<managed_type> &;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename managed_type>
|
|
|
|
class valptridx<managed_type>::vc :
|
|
|
|
public partial_policy::require_valid,
|
|
|
|
public partial_policy::template apply_cv_policy<typename partial_policy::const_policy>
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename managed_type>
|
|
|
|
class valptridx<managed_type>::vm :
|
|
|
|
public partial_policy::require_valid,
|
|
|
|
public partial_policy::template apply_cv_policy<typename partial_policy::mutable_policy>
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename managed_type>
|
|
|
|
class valptridx<managed_type>::ic :
|
|
|
|
public partial_policy::allow_invalid,
|
|
|
|
public partial_policy::template apply_cv_policy<typename partial_policy::const_policy>
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename managed_type>
|
|
|
|
class valptridx<managed_type>::im :
|
|
|
|
public partial_policy::allow_invalid,
|
|
|
|
public partial_policy::template apply_cv_policy<typename partial_policy::mutable_policy>
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename managed_type>
|
2015-08-07 03:13:51 +00:00
|
|
|
template <typename policy, unsigned>
|
2015-07-09 03:12:45 +00:00
|
|
|
class valptridx<managed_type>::basic_idx :
|
|
|
|
public policy
|
|
|
|
{
|
|
|
|
using containing_type = valptridx<managed_type>;
|
|
|
|
public:
|
|
|
|
using policy::allow_nullptr;
|
|
|
|
using policy::check_allowed_invalid_index;
|
|
|
|
using index_type = typename containing_type::index_type;
|
|
|
|
using integral_type = typename containing_type::integral_type;
|
|
|
|
using typename policy::array_managed_type;
|
|
|
|
basic_idx() = delete;
|
|
|
|
basic_idx(const basic_idx &) = default;
|
|
|
|
basic_idx(basic_idx &&) = default;
|
|
|
|
basic_idx &operator=(const basic_idx &) = default;
|
|
|
|
basic_idx &operator=(basic_idx &&) = default;
|
|
|
|
|
|
|
|
index_type get_unchecked_index() const { return m_idx; }
|
|
|
|
|
2015-08-07 03:13:51 +00:00
|
|
|
template <typename rpolicy, unsigned ru>
|
|
|
|
basic_idx(const basic_idx<rpolicy, ru> &rhs, array_managed_type &a = get_array()) :
|
2015-07-09 03:12:45 +00:00
|
|
|
m_idx(rhs.get_unchecked_index())
|
|
|
|
{
|
|
|
|
if (!(allow_nullptr || !rhs.allow_nullptr))
|
|
|
|
check_index_range(m_idx, a);
|
|
|
|
}
|
2015-08-07 03:13:51 +00:00
|
|
|
template <typename rpolicy, unsigned ru>
|
|
|
|
basic_idx(basic_idx<rpolicy, ru> &&rhs) :
|
2015-07-09 03:12:45 +00:00
|
|
|
m_idx(rhs.get_unchecked_index())
|
2014-09-12 03:22:34 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
/* Prevent move from allow_invalid into require_valid. The
|
|
|
|
* right hand side must be saved and checked for validity before
|
|
|
|
* being used to initialize a require_valid type.
|
|
|
|
*/
|
|
|
|
static_assert(allow_nullptr || !rhs.allow_nullptr, "cannot move from allow_invalid to require_valid");
|
2014-09-12 03:22:34 +00:00
|
|
|
}
|
2015-07-09 03:12:45 +00:00
|
|
|
basic_idx(index_type i, array_managed_type &a = get_array()) : // default argument deprecated
|
|
|
|
m_idx(check_allowed_invalid_index(i) ? i : check_index_range(i, a))
|
2014-09-12 03:22:34 +00:00
|
|
|
{
|
|
|
|
}
|
2015-07-09 03:12:45 +00:00
|
|
|
template <integral_type v>
|
|
|
|
basic_idx(const magic_constant<v> &) :
|
|
|
|
m_idx(v)
|
|
|
|
{
|
2015-08-06 02:57:58 +00:00
|
|
|
static_assert(allow_nullptr || static_cast<std::size_t>(v) < get_array_size(), "invalid magic index not allowed for this policy");
|
2015-07-09 03:12:45 +00:00
|
|
|
}
|
2015-08-07 03:13:51 +00:00
|
|
|
template <typename rpolicy, unsigned ru>
|
|
|
|
bool operator==(const basic_idx<rpolicy, ru> &rhs) const
|
2015-07-09 03:12:45 +00:00
|
|
|
{
|
|
|
|
return m_idx == rhs.get_unchecked_index();
|
|
|
|
}
|
|
|
|
bool operator==(const index_type &i) const
|
2014-09-12 03:22:34 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
return m_idx == i;
|
2014-09-12 03:22:34 +00:00
|
|
|
}
|
|
|
|
template <integral_type v>
|
2014-07-11 03:14:50 +00:00
|
|
|
bool operator==(const magic_constant<v> &) const
|
|
|
|
{
|
2015-08-06 02:57:58 +00:00
|
|
|
static_assert(allow_nullptr || static_cast<std::size_t>(v) < get_array_size(), "invalid magic index not allowed for this policy");
|
2015-07-09 03:12:45 +00:00
|
|
|
return m_idx == v;
|
2014-07-11 03:14:50 +00:00
|
|
|
}
|
|
|
|
template <typename R>
|
|
|
|
bool operator!=(const R &rhs) const
|
|
|
|
{
|
|
|
|
return !(*this == rhs);
|
|
|
|
}
|
2015-07-09 03:12:45 +00:00
|
|
|
operator index_type() const
|
2014-09-12 03:22:34 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
return m_idx;
|
2014-09-12 03:22:34 +00:00
|
|
|
}
|
|
|
|
protected:
|
2015-07-09 03:12:45 +00:00
|
|
|
index_type m_idx;
|
2014-09-12 03:22:34 +00:00
|
|
|
};
|
|
|
|
|
2015-07-09 03:12:45 +00:00
|
|
|
template <typename managed_type>
|
2015-08-07 03:13:51 +00:00
|
|
|
template <typename policy, unsigned>
|
2015-07-09 03:12:45 +00:00
|
|
|
class valptridx<managed_type>::basic_ptr :
|
|
|
|
public policy
|
Workaround compilers mishandling template-template arguments
Visual Studio 2013 Update 4 and Clang 3.4 fail to parse
valptridx_template_t related argument lists because they misinterpret
the unspecialized inner template name as a reference to the current
specialization. This seems to be nonconforming in C++11.
All gcc versions supported by Rebirth parse this sample program
correctly, but neither Visual Studio nor clang accept it.
template <template <typename> class>
struct A
{
};
template <typename>
struct B
{
B(A<B>);
};
In <https://stackoverflow.com/questions/17687459/clang-not-accepting-use-of-template-template-parameter-when-using-crtp>, a user saw a similar failure and received the answer:
Your code is legal.
From the C++11 Standard, section 14.6.1:
Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected-class-name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type- specifier of a friend class template declaration, it refers to the class template itself.
Looks like your version of clang is still implementing the old rule.
This failure was first seen with Visual Studio 2013, but ignored because
Visual Studio has so many other problems parsing Rebirth. Now that it
has been reported to affect clang as well, a workaround is clearly
needed. A fix was suggested by btb
<https://github.com/btb/dxx-rebirth/commit/2f9543f9812b584ecf1210dee0ac39f738ecd685>,
but that fix breaks gcc.
Rewrite the valptridx_template_t parameter passing to avoid mentioning
unspecialized template names as template parameters while defining the
class used as the parameter.
Reported by btb (clang): https://github.com/dxx-rebirth/dxx-rebirth/pull/12
2014-11-30 23:44:52 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
using containing_type = valptridx<managed_type>;
|
|
|
|
public:
|
|
|
|
using policy::allow_nullptr;
|
|
|
|
using policy::check_allowed_invalid_index;
|
|
|
|
using const_pointer_type = typename containing_type::const_pointer_type;
|
|
|
|
using mutable_pointer_type = typename containing_type::mutable_pointer_type;
|
|
|
|
using typename policy::array_managed_type;
|
|
|
|
using typename policy::pointer_type;
|
|
|
|
using typename policy::reference_type;
|
Workaround compilers mishandling template-template arguments
Visual Studio 2013 Update 4 and Clang 3.4 fail to parse
valptridx_template_t related argument lists because they misinterpret
the unspecialized inner template name as a reference to the current
specialization. This seems to be nonconforming in C++11.
All gcc versions supported by Rebirth parse this sample program
correctly, but neither Visual Studio nor clang accept it.
template <template <typename> class>
struct A
{
};
template <typename>
struct B
{
B(A<B>);
};
In <https://stackoverflow.com/questions/17687459/clang-not-accepting-use-of-template-template-parameter-when-using-crtp>, a user saw a similar failure and received the answer:
Your code is legal.
From the C++11 Standard, section 14.6.1:
Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected-class-name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type- specifier of a friend class template declaration, it refers to the class template itself.
Looks like your version of clang is still implementing the old rule.
This failure was first seen with Visual Studio 2013, but ignored because
Visual Studio has so many other problems parsing Rebirth. Now that it
has been reported to affect clang as well, a workaround is clearly
needed. A fix was suggested by btb
<https://github.com/btb/dxx-rebirth/commit/2f9543f9812b584ecf1210dee0ac39f738ecd685>,
but that fix breaks gcc.
Rewrite the valptridx_template_t parameter passing to avoid mentioning
unspecialized template names as template parameters while defining the
class used as the parameter.
Reported by btb (clang): https://github.com/dxx-rebirth/dxx-rebirth/pull/12
2014-11-30 23:44:52 +00:00
|
|
|
|
2015-07-09 03:12:45 +00:00
|
|
|
basic_ptr() = delete;
|
|
|
|
/* Override template matches to make same-type copy/move trivial */
|
|
|
|
basic_ptr(const basic_ptr &) = default;
|
|
|
|
basic_ptr(basic_ptr &&) = default;
|
|
|
|
basic_ptr &operator=(const basic_ptr &) = default;
|
|
|
|
basic_ptr &operator=(basic_ptr &&) = default;
|
Workaround compilers mishandling template-template arguments
Visual Studio 2013 Update 4 and Clang 3.4 fail to parse
valptridx_template_t related argument lists because they misinterpret
the unspecialized inner template name as a reference to the current
specialization. This seems to be nonconforming in C++11.
All gcc versions supported by Rebirth parse this sample program
correctly, but neither Visual Studio nor clang accept it.
template <template <typename> class>
struct A
{
};
template <typename>
struct B
{
B(A<B>);
};
In <https://stackoverflow.com/questions/17687459/clang-not-accepting-use-of-template-template-parameter-when-using-crtp>, a user saw a similar failure and received the answer:
Your code is legal.
From the C++11 Standard, section 14.6.1:
Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected-class-name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type- specifier of a friend class template declaration, it refers to the class template itself.
Looks like your version of clang is still implementing the old rule.
This failure was first seen with Visual Studio 2013, but ignored because
Visual Studio has so many other problems parsing Rebirth. Now that it
has been reported to affect clang as well, a workaround is clearly
needed. A fix was suggested by btb
<https://github.com/btb/dxx-rebirth/commit/2f9543f9812b584ecf1210dee0ac39f738ecd685>,
but that fix breaks gcc.
Rewrite the valptridx_template_t parameter passing to avoid mentioning
unspecialized template names as template parameters while defining the
class used as the parameter.
Reported by btb (clang): https://github.com/dxx-rebirth/dxx-rebirth/pull/12
2014-11-30 23:44:52 +00:00
|
|
|
|
2015-07-09 03:12:45 +00:00
|
|
|
pointer_type get_unchecked_pointer() const { return m_ptr; }
|
|
|
|
|
|
|
|
basic_ptr(std::nullptr_t) :
|
|
|
|
m_ptr(nullptr)
|
2014-08-23 23:53:56 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
static_assert(allow_nullptr, "nullptr construction not allowed for this policy");
|
2014-08-23 23:53:56 +00:00
|
|
|
}
|
2014-09-12 03:22:34 +00:00
|
|
|
template <integral_type v>
|
2015-07-09 03:12:45 +00:00
|
|
|
basic_ptr(const magic_constant<v> &) :
|
2015-07-13 01:09:37 +00:00
|
|
|
m_ptr(nullptr)
|
2014-07-11 03:14:50 +00:00
|
|
|
{
|
2015-08-06 02:57:58 +00:00
|
|
|
static_assert(static_cast<std::size_t>(v) >= get_array_size(), "valid magic index requires an array");
|
|
|
|
static_assert(allow_nullptr || static_cast<std::size_t>(v) < get_array_size(), "invalid magic index not allowed for this policy");
|
2014-07-11 03:14:50 +00:00
|
|
|
}
|
2015-07-13 01:09:37 +00:00
|
|
|
template <integral_type v>
|
|
|
|
basic_ptr(const magic_constant<v> &, array_managed_type &a) :
|
2015-08-06 02:57:58 +00:00
|
|
|
m_ptr(static_cast<std::size_t>(v) < get_array_size() ? &(a[v]) : nullptr)
|
2015-07-13 01:09:37 +00:00
|
|
|
{
|
2015-08-06 02:57:58 +00:00
|
|
|
static_assert(allow_nullptr || static_cast<std::size_t>(v) < get_array_size(), "invalid magic index not allowed for this policy");
|
2015-07-13 01:09:37 +00:00
|
|
|
}
|
2015-08-07 03:13:51 +00:00
|
|
|
template <typename rpolicy, unsigned ru>
|
2015-08-22 20:43:04 +00:00
|
|
|
basic_ptr(const basic_ptr<rpolicy, ru> &rhs) :
|
2015-07-09 03:12:45 +00:00
|
|
|
m_ptr(rhs.get_unchecked_pointer())
|
2014-08-16 23:13:17 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
if (!(allow_nullptr || !rhs.allow_nullptr))
|
2015-08-22 20:43:04 +00:00
|
|
|
check_null_pointer_conversion(m_ptr);
|
2014-08-16 23:13:17 +00:00
|
|
|
}
|
2015-08-07 03:13:51 +00:00
|
|
|
template <typename rpolicy, unsigned ru>
|
|
|
|
basic_ptr(basic_ptr<rpolicy, ru> &&rhs) :
|
2015-07-09 03:12:45 +00:00
|
|
|
m_ptr(rhs.get_unchecked_pointer())
|
2014-07-11 03:14:50 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
/* Prevent move from allow_invalid into require_valid. The
|
|
|
|
* right hand side must be saved and checked for validity before
|
|
|
|
* being used to initialize a require_valid type.
|
|
|
|
*/
|
|
|
|
static_assert(allow_nullptr || !rhs.allow_nullptr, "cannot move from allow_invalid to require_valid");
|
2013-12-24 04:53:59 +00:00
|
|
|
}
|
2015-07-09 03:12:45 +00:00
|
|
|
basic_ptr(index_type i, array_managed_type &a = get_array()) :
|
|
|
|
m_ptr(check_allowed_invalid_index(i) ? nullptr : &a[check_index_range(i, a)])
|
2014-07-11 03:14:50 +00:00
|
|
|
{
|
|
|
|
}
|
2015-07-09 03:12:45 +00:00
|
|
|
basic_ptr(pointer_type p, array_managed_type &a = get_array()) :
|
|
|
|
m_ptr(p)
|
2014-09-12 03:22:34 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
if (!allow_nullptr)
|
|
|
|
check_null_pointer(p, a);
|
2014-09-12 03:22:34 +00:00
|
|
|
}
|
2015-07-29 03:05:28 +00:00
|
|
|
basic_ptr(reference_type r, array_managed_type &a) :
|
2015-07-09 03:12:45 +00:00
|
|
|
m_ptr((check_implicit_index_range_ref(r, a), &r))
|
2014-07-11 03:14:50 +00:00
|
|
|
{
|
2014-01-10 03:58:03 +00:00
|
|
|
}
|
2015-07-29 03:05:28 +00:00
|
|
|
basic_ptr(reference_type r, index_type i, array_managed_type &a) :
|
2015-07-09 03:12:45 +00:00
|
|
|
m_ptr((check_explicit_index_range_ref(r, i, a), &r))
|
2014-09-12 03:22:34 +00:00
|
|
|
{
|
|
|
|
}
|
2014-01-10 03:58:03 +00:00
|
|
|
|
2015-07-09 03:12:45 +00:00
|
|
|
operator mutable_pointer_type() const { return m_ptr; } // implicit pointer conversion deprecated
|
|
|
|
operator const_pointer_type() const { return m_ptr; } // implicit pointer conversion deprecated
|
|
|
|
pointer_type operator->() const DXX_VALPTRIDX_REF_QUALIFIER_LVALUE
|
2014-08-13 02:44:59 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
return m_ptr;
|
2014-08-13 02:44:59 +00:00
|
|
|
}
|
2015-07-09 03:12:45 +00:00
|
|
|
operator reference_type() const DXX_VALPTRIDX_REF_QUALIFIER_LVALUE
|
2014-10-02 03:02:34 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
return *m_ptr;
|
2014-10-02 03:02:34 +00:00
|
|
|
}
|
2015-07-09 03:12:45 +00:00
|
|
|
reference_type operator*() const DXX_VALPTRIDX_REF_QUALIFIER_LVALUE
|
2014-08-13 02:44:59 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
return *this;
|
2014-08-13 02:44:59 +00:00
|
|
|
}
|
2015-07-09 03:12:45 +00:00
|
|
|
explicit operator bool() const DXX_VALPTRIDX_REF_QUALIFIER_LVALUE
|
2014-09-12 03:22:34 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
return !(*this == nullptr);
|
2014-09-12 03:22:34 +00:00
|
|
|
}
|
2015-07-09 03:12:45 +00:00
|
|
|
#ifdef DXX_HAVE_CXX11_REF_QUALIFIER
|
|
|
|
pointer_type operator->() const &&
|
2014-11-23 04:58:45 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
static_assert(!allow_nullptr, "operator-> not allowed with allow_invalid policy");
|
|
|
|
return operator->();
|
2014-11-23 04:58:45 +00:00
|
|
|
}
|
2015-07-09 03:12:45 +00:00
|
|
|
operator reference_type() const &&
|
2014-09-12 03:22:34 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
static_assert(!allow_nullptr, "implicit reference not allowed with allow_invalid policy");
|
|
|
|
return *this;
|
2014-09-12 03:22:34 +00:00
|
|
|
}
|
2015-07-09 03:12:45 +00:00
|
|
|
reference_type operator*() const &&
|
2014-10-02 03:02:34 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
static_assert(!allow_nullptr, "operator* not allowed with allow_invalid policy");
|
|
|
|
return *this;
|
2014-10-02 03:02:34 +00:00
|
|
|
}
|
2015-07-09 03:12:45 +00:00
|
|
|
explicit operator bool() const && = delete;
|
|
|
|
#endif
|
|
|
|
bool operator==(std::nullptr_t) const
|
2014-10-02 03:02:34 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
static_assert(allow_nullptr, "nullptr comparison not allowed: value is never null");
|
|
|
|
return m_ptr == nullptr;
|
2014-10-02 03:02:34 +00:00
|
|
|
}
|
2015-07-09 03:12:45 +00:00
|
|
|
bool operator==(const_pointer_type p) const
|
2014-10-02 03:02:34 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
return m_ptr == p;
|
2014-10-02 03:02:34 +00:00
|
|
|
}
|
2015-07-09 03:12:45 +00:00
|
|
|
bool operator==(mutable_pointer_type p) const
|
2014-10-02 03:02:34 +00:00
|
|
|
{
|
2015-07-09 03:12:45 +00:00
|
|
|
return m_ptr == p;
|
2014-10-02 03:02:34 +00:00
|
|
|
}
|
2015-08-07 03:13:51 +00:00
|
|
|
template <typename rpolicy, unsigned ru>
|
|
|
|
bool operator==(const basic_ptr<rpolicy, ru> &rhs) const
|
2015-07-09 03:12:45 +00:00
|
|
|
{
|
|
|
|
return *this == rhs.get_unchecked_pointer();
|
|
|
|
}
|
2014-10-02 03:02:34 +00:00
|
|
|
template <typename R>
|
|
|
|
bool operator!=(const R &rhs) const
|
|
|
|
{
|
|
|
|
return !(*this == rhs);
|
|
|
|
}
|
2015-07-09 03:12:45 +00:00
|
|
|
template <typename U>
|
|
|
|
long operator-(U) const = delete;
|
|
|
|
template <typename R>
|
|
|
|
bool operator<(R) const = delete;
|
|
|
|
template <typename R>
|
|
|
|
bool operator>(R) const = delete;
|
|
|
|
template <typename R>
|
|
|
|
bool operator<=(R) const = delete;
|
|
|
|
template <typename R>
|
|
|
|
bool operator>=(R) const = delete;
|
|
|
|
protected:
|
|
|
|
pointer_type m_ptr;
|
2014-09-12 03:22:34 +00:00
|
|
|
};
|
|
|
|
|
2015-07-09 03:12:45 +00:00
|
|
|
template <typename managed_type>
|
|
|
|
template <typename policy>
|
|
|
|
class valptridx<managed_type>::basic_ptridx :
|
2015-08-06 02:57:59 +00:00
|
|
|
public prohibit_void_ptr<basic_ptridx<policy>>,
|
2015-08-07 03:13:51 +00:00
|
|
|
public basic_ptr<policy, 1>,
|
|
|
|
public basic_idx<policy, 1>
|
2014-09-12 03:22:34 +00:00
|
|
|
{
|
|
|
|
public:
|
2015-08-07 03:13:51 +00:00
|
|
|
typedef basic_ptr<policy, 1> vptr_type;
|
|
|
|
typedef basic_idx<policy, 1> vidx_type;
|
2015-07-09 03:12:45 +00:00
|
|
|
using typename vidx_type::array_managed_type;
|
|
|
|
using typename vidx_type::index_type;
|
|
|
|
using typename vidx_type::integral_type;
|
|
|
|
using typename vptr_type::pointer_type;
|
|
|
|
using vidx_type::operator==;
|
|
|
|
using vptr_type::operator==;
|
|
|
|
basic_ptridx(const basic_ptridx &) = default;
|
|
|
|
basic_ptridx(basic_ptridx &&) = default;
|
|
|
|
basic_ptridx &operator=(const basic_ptridx &) = default;
|
|
|
|
basic_ptridx &operator=(basic_ptridx &&) = default;
|
2015-07-13 01:09:37 +00:00
|
|
|
basic_ptridx(std::nullptr_t) = delete;
|
|
|
|
/* Prevent implicit conversion. Require use of the factory function.
|
|
|
|
*/
|
|
|
|
basic_ptridx(pointer_type p) = delete;
|
2015-07-09 03:12:45 +00:00
|
|
|
template <typename rpolicy>
|
|
|
|
basic_ptridx(const basic_ptridx<rpolicy> &rhs) :
|
2015-08-07 03:13:51 +00:00
|
|
|
vptr_type(static_cast<const typename basic_ptridx<rpolicy>::vptr_type &>(rhs)),
|
|
|
|
vidx_type(static_cast<const typename basic_ptridx<rpolicy>::vidx_type &>(rhs))
|
2014-08-23 23:53:56 +00:00
|
|
|
{
|
|
|
|
}
|
2015-07-09 03:12:45 +00:00
|
|
|
template <typename rpolicy>
|
|
|
|
basic_ptridx(basic_ptridx<rpolicy> &&rhs) :
|
2015-08-07 03:13:51 +00:00
|
|
|
vptr_type(static_cast<typename basic_ptridx<rpolicy>::vptr_type &&>(rhs)),
|
|
|
|
vidx_type(static_cast<typename basic_ptridx<rpolicy>::vidx_type &&>(rhs))
|
2014-08-13 02:44:59 +00:00
|
|
|
{
|
|
|
|
}
|
2015-07-09 03:12:45 +00:00
|
|
|
template <integral_type v>
|
2015-07-29 03:05:28 +00:00
|
|
|
basic_ptridx(const magic_constant<v> &m) :
|
|
|
|
vptr_type(m),
|
|
|
|
vidx_type(m)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
template <integral_type v>
|
|
|
|
basic_ptridx(const magic_constant<v> &m, array_managed_type &a) :
|
2015-07-13 01:09:37 +00:00
|
|
|
vptr_type(m, a),
|
2015-07-09 03:12:45 +00:00
|
|
|
vidx_type(m)
|
2014-08-13 02:44:59 +00:00
|
|
|
{
|
|
|
|
}
|
2015-07-09 03:12:45 +00:00
|
|
|
basic_ptridx(index_type i, array_managed_type &a = get_array()) : // default argument deprecated
|
|
|
|
vptr_type(i, a),
|
|
|
|
vidx_type(i, a)
|
2014-08-13 02:44:59 +00:00
|
|
|
{
|
|
|
|
}
|
2015-07-13 01:09:37 +00:00
|
|
|
basic_ptridx(pointer_type p, array_managed_type &a) :
|
2015-07-09 03:12:45 +00:00
|
|
|
/* Null pointer is never allowed when an index must be computed.
|
|
|
|
* Check for null, then use the reference constructor for
|
|
|
|
* vptr_type to avoid checking again.
|
|
|
|
*/
|
|
|
|
vptr_type((check_null_pointer(p, a), *p), a),
|
2015-09-15 02:48:04 +00:00
|
|
|
vidx_type(p - static_cast<pointer_type>(&a.front()), a)
|
2014-08-13 02:44:59 +00:00
|
|
|
{
|
|
|
|
}
|
2015-07-29 03:05:28 +00:00
|
|
|
basic_ptridx(pointer_type p, index_type i, array_managed_type &a) :
|
2015-07-09 03:12:45 +00:00
|
|
|
vptr_type((check_null_pointer(p, a), *p), i, a),
|
|
|
|
vidx_type(i, a)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
template <typename rpolicy>
|
|
|
|
bool operator==(const basic_ptridx<rpolicy> &rhs) const
|
2014-08-13 02:44:59 +00:00
|
|
|
{
|
2015-08-07 03:13:51 +00:00
|
|
|
return vptr_type::operator==(static_cast<const typename basic_ptridx<rpolicy>::vptr_type &>(rhs));
|
2014-08-13 02:44:59 +00:00
|
|
|
}
|
|
|
|
template <typename R>
|
|
|
|
bool operator!=(const R &rhs) const
|
|
|
|
{
|
|
|
|
return !(*this == rhs);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-08-22 20:43:04 +00:00
|
|
|
template <typename managed_type>
|
|
|
|
class valptridx<managed_type>::array_managed_type : public array<managed_type, get_array_size()>
|
|
|
|
{
|
|
|
|
using containing_type = valptridx<managed_type>;
|
|
|
|
using array_type = array<managed_type, get_array_size()>;
|
|
|
|
public:
|
|
|
|
using typename array_type::reference;
|
|
|
|
using typename array_type::const_reference;
|
|
|
|
using index_type = typename containing_type::index_type;
|
|
|
|
unsigned highest;
|
|
|
|
template <typename T>
|
|
|
|
typename tt::enable_if<tt::is_integral<T>::value, reference>::type operator[](T n)
|
|
|
|
{
|
|
|
|
return array_type::operator[](n);
|
|
|
|
}
|
|
|
|
template <typename T>
|
|
|
|
typename tt::enable_if<tt::is_integral<T>::value, const_reference>::type operator[](T n) const
|
|
|
|
{
|
|
|
|
return array_type::operator[](n);
|
|
|
|
}
|
|
|
|
template <typename T>
|
|
|
|
typename tt::enable_if<!tt::is_integral<T>::value, reference>::type operator[](T) const = delete;
|
|
|
|
#if DXX_HAVE_POISON_UNDEFINED
|
|
|
|
array_managed_type();
|
|
|
|
#else
|
|
|
|
array_managed_type() = default;
|
|
|
|
#endif
|
|
|
|
array_managed_type(const array_managed_type &) = delete;
|
|
|
|
array_managed_type &operator=(const array_managed_type &) = delete;
|
|
|
|
};
|
|
|
|
|
2015-07-09 03:12:45 +00:00
|
|
|
template <typename managed_type>
|
2015-07-13 01:09:37 +00:00
|
|
|
template <typename P>
|
2015-07-13 01:09:36 +00:00
|
|
|
class valptridx<managed_type>::basic_vptr_global_factory
|
2015-07-09 03:12:45 +00:00
|
|
|
{
|
2015-07-29 03:05:28 +00:00
|
|
|
using containing_type = valptridx<managed_type>;
|
2015-07-09 03:12:45 +00:00
|
|
|
public:
|
2015-08-22 20:43:04 +00:00
|
|
|
basic_vptr_global_factory() = default;
|
|
|
|
basic_vptr_global_factory(const basic_vptr_global_factory &) = delete;
|
|
|
|
basic_vptr_global_factory &operator=(const basic_vptr_global_factory &) = delete;
|
2015-07-13 01:09:36 +00:00
|
|
|
__attribute_warn_unused_result
|
2015-07-13 01:09:37 +00:00
|
|
|
P operator()(typename P::const_pointer_type p) const
|
2015-05-09 17:38:58 +00:00
|
|
|
{
|
2015-07-13 01:09:37 +00:00
|
|
|
return P(p, get_array(p));
|
2015-05-09 17:38:58 +00:00
|
|
|
}
|
2015-07-13 01:09:36 +00:00
|
|
|
__attribute_warn_unused_result
|
2015-07-13 01:09:37 +00:00
|
|
|
P operator()(typename P::mutable_pointer_type p) const
|
2014-11-25 04:02:01 +00:00
|
|
|
{
|
2015-07-13 01:09:37 +00:00
|
|
|
return P(p, get_array(p));
|
2014-11-25 04:02:01 +00:00
|
|
|
}
|
2015-07-13 01:09:36 +00:00
|
|
|
__attribute_warn_unused_result
|
2015-07-29 03:05:28 +00:00
|
|
|
P operator()(typename containing_type::index_type i) const
|
2014-11-25 04:02:01 +00:00
|
|
|
{
|
2015-07-13 01:09:37 +00:00
|
|
|
return P(i, get_array());
|
2014-11-25 04:02:01 +00:00
|
|
|
}
|
2015-07-29 03:05:28 +00:00
|
|
|
template <containing_type::integral_type v>
|
|
|
|
__attribute_warn_unused_result
|
|
|
|
P operator()(const containing_type::magic_constant<v> &m) const
|
|
|
|
{
|
|
|
|
return P(m, get_array());
|
|
|
|
}
|
2014-11-25 04:02:01 +00:00
|
|
|
template <typename T>
|
2015-07-13 01:09:37 +00:00
|
|
|
P operator()(T &&) const = delete;
|
2015-06-13 22:42:15 +00:00
|
|
|
void *operator &() const = delete;
|
2014-11-25 04:02:01 +00:00
|
|
|
};
|
|
|
|
|
2015-07-09 03:12:45 +00:00
|
|
|
template <typename managed_type>
|
2015-07-13 01:09:37 +00:00
|
|
|
template <typename PI>
|
2015-07-09 03:12:45 +00:00
|
|
|
class valptridx<managed_type>::basic_ptridx_global_factory
|
2014-11-25 04:02:01 +00:00
|
|
|
{
|
2015-07-13 01:09:37 +00:00
|
|
|
using containing_type = valptridx<managed_type>;
|
2015-07-09 03:12:45 +00:00
|
|
|
public:
|
2015-08-22 20:43:04 +00:00
|
|
|
basic_ptridx_global_factory() = default;
|
|
|
|
basic_ptridx_global_factory(const basic_ptridx_global_factory &) = delete;
|
|
|
|
basic_ptridx_global_factory &operator=(const basic_ptridx_global_factory &) = delete;
|
2015-07-13 01:09:36 +00:00
|
|
|
__attribute_warn_unused_result
|
2015-07-13 01:09:37 +00:00
|
|
|
PI operator()(typename PI::index_type i) const
|
2014-11-25 04:02:01 +00:00
|
|
|
{
|
2015-07-13 01:09:37 +00:00
|
|
|
return PI(i, get_array());
|
2014-11-25 04:02:01 +00:00
|
|
|
}
|
2015-07-13 01:09:37 +00:00
|
|
|
template <containing_type::integral_type v>
|
|
|
|
__attribute_warn_unused_result
|
2015-07-13 01:09:37 +00:00
|
|
|
PI operator()(const containing_type::magic_constant<v> &m) const
|
2015-07-13 01:09:37 +00:00
|
|
|
{
|
2015-07-13 01:09:37 +00:00
|
|
|
return PI(m, get_array());
|
2015-07-13 01:09:37 +00:00
|
|
|
}
|
2014-11-25 04:02:01 +00:00
|
|
|
template <typename T>
|
2015-07-13 01:09:37 +00:00
|
|
|
PI operator()(T &&) const = delete;
|
2015-06-13 22:42:15 +00:00
|
|
|
void *operator &() const = delete;
|
2014-11-25 04:02:01 +00:00
|
|
|
};
|
|
|
|
|
2014-10-02 03:02:34 +00:00
|
|
|
#define _DEFINE_VALPTRIDX_SUBTYPE_USERTYPE(N,P,I,A,prefix,Pconst) \
|
2015-07-13 01:09:36 +00:00
|
|
|
constexpr valptridx<P>::basic_vptr_global_factory<v##prefix##ptr_t> v##prefix##ptr{}; \
|
2015-07-09 03:12:45 +00:00
|
|
|
constexpr valptridx<P>::basic_ptridx_global_factory<prefix##ptridx_t> prefix##ptridx{}; \
|
2015-07-13 01:09:36 +00:00
|
|
|
constexpr valptridx<P>::basic_vptr_global_factory<v##prefix##ptridx_t> v##prefix##ptridx{}; \
|
2014-10-02 03:02:34 +00:00
|
|
|
static inline v##prefix##ptridx_t operator-(P Pconst *o, decltype(A) Pconst &O) \
|
2014-07-27 03:45:26 +00:00
|
|
|
{ \
|
2015-09-15 02:48:04 +00:00
|
|
|
return {o, static_cast<v##prefix##ptridx_t::integral_type>(const_cast<const P *>(o) - static_cast<const P *>(&(const_cast<const decltype(A) &>(O).front()))), A}; \
|
2014-07-27 03:45:26 +00:00
|
|
|
} \
|
2014-07-11 03:14:50 +00:00
|
|
|
|
|
|
|
#define DEFINE_VALPTRIDX_SUBTYPE(N,P,I,A) \
|
2014-10-02 03:02:34 +00:00
|
|
|
static inline constexpr decltype(A) &get_global_array(P *) { return A; } \
|
|
|
|
/* "decltype(A) const &" parses correctly, but fails to match */ \
|
|
|
|
static inline constexpr typename tt::add_const<decltype(A)>::type &get_global_array(P const *) { return A; } \
|
|
|
|
\
|
|
|
|
_DEFINE_VALPTRIDX_SUBTYPE_USERTYPE(N,P,I,A,N,); \
|
|
|
|
_DEFINE_VALPTRIDX_SUBTYPE_USERTYPE(N,P,I,A,c##N,const) \
|
2013-12-24 04:53:59 +00:00
|
|
|
|