diff --git a/src/core/model/attribute-container-accessor-helper.h b/src/core/model/attribute-container-accessor-helper.h index 509f4f1b4..0b6a6cb63 100644 --- a/src/core/model/attribute-container-accessor-helper.h +++ b/src/core/model/attribute-container-accessor-helper.h @@ -31,15 +31,67 @@ namespace ns3 { +/** + * Compile time check if type T has const iterator. + */ +template +struct has_const_iterator +{ +private: + typedef char yes; + typedef struct { char array[2]; } no; + + template static yes test(typename C::const_iterator*); + template static no test(...); +public: + static const bool value = sizeof(test(0)) == sizeof(yes); + typedef T type; +}; + +/** + * Compile time check if type T has begin() and end() methods. + */ +template +struct has_begin_end +{ + template static char (&f(typename std::enable_if< + std::is_same(&C::begin)), + typename C::const_iterator(C::*)() const>::value, void>::type*))[1]; + + template static char (&f(...))[2]; + + template static char (&g(typename std::enable_if< + std::is_same(&C::end)), + typename C::const_iterator(C::*)() const>::value, void>::type*))[1]; + + template static char (&g(...))[2]; + + static bool const beg_value = sizeof(f(0)) == 1; + static bool const end_value = sizeof(g(0)) == 1; +}; + +/** + * Compile time check if type T is a container. + * + * Container here means has an iterator and supports begin() and end() + * methods. + * + * Can be used when defining specializations when a type T is an STL + * like container. + */ +template +struct is_container : std::integral_constant::value && has_begin_end::beg_value && has_begin_end::end_value> +{ }; + /** * \ingroup attributeimpl * * DoMakeAccessorHelperOne specialization for member containers * - * The template parameter list contains an extra parameter that disambiguates - * the templated Ptr type from container types by taking advantage of the fact - * that container types have multiple template arguments and Ptr has only one. - * This disambiguation works but is not sufficiently robust as a long term solution. + * The template parameter list contains an extra parameter that is + * intended to disambiguate an attribute container from any other + * templated attribute, e.g Ptr or Callback. Disambiguation is based + * on begin/end and iterator. * * \tparam V \explicit The specific AttributeValue type to use to represent * the Attribute. @@ -50,7 +102,7 @@ namespace ns3 { * \returns The AttributeAccessor. */ template class U, typename ...I, - typename = typename std::enable_if< (sizeof...(I) > 1), void>::type > + typename = typename std::enable_if< ( is_container< U >::value ), void>::type > inline Ptr DoMakeAccessorHelperOne (U T::*memberContainer) @@ -98,4 +150,4 @@ DoMakeAccessorHelperOne (U T::*memberContainer) } // namespace ns3 -#endif // ATTRIBUTE_CONTAINER_ACCESSOR_HELPER_H \ No newline at end of file +#endif // ATTRIBUTE_CONTAINER_ACCESSOR_HELPER_H