constexpr14_namespace_check.cpp 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // Copyright 2013-2019 Antony Polukhin
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See the accompanying file LICENSE_1_0.txt
  4. // or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)
  5. #include <boost/config.hpp>
  6. template <class T>
  7. void do_something(const T&) {}
  8. #if !defined(BOOST_NO_CXX14_CONSTEXPR) && !defined(BOOST_NO_CXX11_CONSTEXPR)
  9. // Implementation of this function is not essential for the example
  10. template <std::size_t N>
  11. constexpr bool starts_with(const char* name, const char (&ns)[N]) noexcept {
  12. for (std::size_t i = 0; i < N - 1; ++i)
  13. if (name[i] != ns[i])
  14. return false;
  15. return true;
  16. }
  17. //[type_index_constexpr14_namespace_example
  18. /*`
  19. The following example shows that `boost::typeindex::ctti_type_index` is usable at compile time on
  20. a C++14 compatible compilers.
  21. In this example we'll create and use a constexpr function that checks namespace of the provided type.
  22. */
  23. #include <boost/type_index/ctti_type_index.hpp>
  24. // Helper function that returns true if `name` starts with `substr`
  25. template <std::size_t N>
  26. constexpr bool starts_with(const char* name, const char (&substr)[N]) noexcept;
  27. // Function that returns true if `T` declared in namespace `ns`
  28. template <class T, std::size_t N>
  29. constexpr bool in_namespace(const char (&ns)[N]) noexcept {
  30. const char* name = boost::typeindex::ctti_type_index::type_id<T>().raw_name();
  31. // Some compilers add `class ` or `struct ` before the namespace, so we need to skip those words first
  32. if (starts_with(name, "class ")) {
  33. name += sizeof("class ") - 1;
  34. } else if (starts_with(name, "struct ")) {
  35. name += sizeof("struct ") - 1;
  36. }
  37. return starts_with(name, ns) && starts_with(name + N - 1, "::");
  38. }
  39. /*`
  40. Now when we have that wonderfull function, we can do static assertions and other compile-time validations:
  41. */
  42. namespace my_project {
  43. struct serializer {
  44. template <class T>
  45. void serialize(const T& value) {
  46. static_assert(
  47. in_namespace<T>("my_project::types") || in_namespace<T>("my_project::types_ext"),
  48. "Only types from namespaces `my_project::types` and `my_project::types_ext` are allowed to be serialized using `my_project::serializer`"
  49. );
  50. // Actual implementation of the serialization goes below
  51. // ...
  52. do_something(value);
  53. }
  54. };
  55. namespace types {
  56. struct foo{};
  57. struct bar{};
  58. }
  59. } // namespace my_project
  60. int main() {
  61. my_project::serializer s;
  62. my_project::types::foo f;
  63. my_project::types::bar b;
  64. s.serialize(f);
  65. s.serialize(b);
  66. // short sh = 0;
  67. // s.serialize(sh); // Fails the static_assert!
  68. }
  69. //] [/type_index_constexpr14_namespace_example]
  70. #else // #if !defined(BOOST_NO_CXX14_CONSTEXPR) && !defined(BOOST_NO_CXX11_CONSTEXPR)
  71. int main() {}
  72. #endif