text: // Range v3 library
  //
  //  Copyright Eric Niebler 2014-present
  //
  //  Use, modification and distribution is subject to the
  //  Boost Software License, Version 1.0. (See accompanying
  //  file LICENSE_1_0.txt or copy at
  //  http://www.boost.org/LICENSE_1_0.txt)
  //
  // Project home: https://github.com/ericniebler/range-v3
  
  #include <utility>
  #include <type_traits>
  #include <range/v3/utility/common_type.hpp>
  #include <range/v3/utility/common_tuple.hpp>
  
  struct B {};
  struct D : B {};
  
  struct noncopyable
  {
      noncopyable() = default;
      noncopyable(noncopyable const &) = delete;
      noncopyable(noncopyable &&) = default;
      noncopyable &operator=(noncopyable const &) = delete;
      noncopyable &operator=(noncopyable &&) = default;
  };
  
  struct noncopyable2 : noncopyable
  {};
  
  struct X {};
  struct Y {};
  struct Z {};
  namespace ranges
  {
      template<>
      struct common_type<X, Y>
      {
          using type = Z;
      };
      template<>
      struct common_type<Y, X>
      {
          using type = Z;
      };
  }
  
  int main()
  {
      using namespace ranges;
      using namespace detail;
      static_assert(std::is_same<common_reference_t<B &, D &>, B &>::value, "");
      static_assert(std::is_same<common_reference_t<B &, D const &>, B const &>::value, "");
      static_assert(std::is_same<common_reference_t<B &, D const &, D &>, B const &>::value, "");
      static_assert(std::is_same<common_reference_t<B const &, D &>, B const &>::value, "");
      static_assert(std::is_same<common_reference_t<B &, D &, B &, D &>, B &>::value, "");
  
      static_assert(std::is_same<common_reference_t<B &&, D &&>, B &&>::value, "");
      static_assert(std::is_same<common_reference_t<B const &&, D &&>, B const &&>::value, "");
      static_assert(std::is_same<common_reference_t<B &&, D const &&>, B const &&>::value, "");
  
      static_assert(std::is_same<common_reference_t<B &, D &&>, B const &>::value, "");
      static_assert(std::is_same<common_reference_t<B &, D const &&>, B const &>::value, "");
      static_assert(std::is_same<common_reference_t<B const &, D &&>, B const &>::value, "");
  
      static_assert(std::is_same<common_reference_t<B &&, D &>, B const &>::value, "");
      static_assert(std::is_same<common_reference_t<B &&, D const &>, B const &>::value, "");
      static_assert(std::is_same<common_reference_t<B const &&, D &>, B const &>::value, "");
  
      static_assert(std::is_same<common_reference_t<int, short>, int>::value, "");
      static_assert(std::is_same<common_reference_t<int, short &>, int>::value, "");
      static_assert(std::is_same<common_reference_t<int &, short &>, int>::value, "");
      static_assert(std::is_same<common_reference_t<int &, short>, int>::value, "");
  
      // tricky volatile reference case
      static_assert(std::is_same<common_reference_t<int &&, int volatile &>, int>::value, "");
      static_assert(std::is_same<common_reference_t<int volatile &, int &&>, int>::value, "");
      static_assert(std::is_same<common_reference_t<int const volatile &&, int volatile &&>, int const volatile &&>::value, "");
      static_assert(std::is_same<common_reference_t<int &&, int const &, int volatile &>, int const volatile &>(), "");
  
      // Array types?? Yup!
      static_assert(std::is_same<common_reference_t<int (&)[10], int (&&)[10]>, int const(&)[10]>::value, "");
      static_assert(std::is_same<common_reference_t<int const (&)[10], int volatile (&)[10]>, int const volatile(&)[10]>::value, "");
      static_assert(std::is_same<common_reference_t<int (&)[10], int (&)[11]>, int *>::value, "");
  
      // Some tests for common_pair with common_reference
      static_assert(std::is_same<
          common_reference_t<std::pair<int &, int &>, common_pair<int,int> const &>,
          common_pair<int const &, int const &>
      >::value, "");
  
      // BUGBUG TODO Is a workaround possible?
  #if !defined(__GNUC__) || __GNUC__ != 4 || __GNUC_MINOR__ > 8
      static_assert(std::is_same<
          common_reference_t<common_pair<int const &, int const &>, std::pair<int, int>>,
          std::pair<int, int>
      >::value, "");
  
      static_assert(std::is_same<
          detail::_builtin_common_t<common_pair<int, int> const &, std::pair<int, int> &>,
          std::pair<int, int> const &
      >::value, "");
  #endif
  
      static_assert(std::is_same<
          common_reference_t<common_pair<int, int> const &, std::pair<int, int> &>,
          std::pair<int, int> const &
      >::value, "");
  
      // Some tests with noncopyable types
      static_assert(std::is_same<
          detail::_builtin_common_t<noncopyable const &, noncopyable>,
          noncopyable
      >::value, "");
  
      static_assert(std::is_same<
          detail::_builtin_common_t<noncopyable2 const &, noncopyable>,
          noncopyable
      >::value, "");
  
      static_assert(std::is_same<
          detail::_builtin_common_t<noncopyable const &, noncopyable2>,
          noncopyable
      >::value, "");
  
      static_assert(std::is_same<
          common_reference_t<X &, Y const &>,
          Z
      >::value, "");
  
      {
          // Regression test for #367
          using CP = common_pair<int, int>;
          CONCEPT_ASSERT(Same<common_type_t<CP, CP>, CP>());
      }
  }
  