Search code examples
c++boostc++20c++-concepts

No type named 'type' in 'struct std::common_reference<Ref&&, const Val&>'


I'm trying to write a proxy iterator using Boost.STLInterfaces. It fails to compile because the lvalue reference of the value and the rvalue reference of the reference are different, see a simplified version on Compiler Explorer https://godbolt.org/z/aE3bq7en4. How do I make two types have common reference? I tried overloading the addressof operator to return the reference type, but compiling a distilled example

#include <type_traits>

class Ref {};
class Val {};

// overload addressof operator
constexpr Ref operator&(Val) noexcept;
constexpr Ref operator&(Ref) noexcept;

int main()
{
  std::common_reference<Ref&&, const Val&>::type t;
  return 0;
}

fails with

error: no type named 'type' in 'std::common_reference<Ref &&, const Val &>'


Solution

  • In this case, you need to partial specialize std::basic_common_reference to define the common reference of the two, similar to this:

    template<template<class> class TQual, template<class> class UQual>
    struct std::basic_common_reference<Ref, Val, TQual, UQual> { 
      using type = Val;
    };
    
    template<template<class> class TQual, template<class> class UQual>
    struct std::basic_common_reference<Val, Ref, TQual, UQual> { 
      using type = Val;
    };
    

    Demo.

    Some issues worth noting:

    • Val's member functions need to be public.
    • Val's constructor should not be explicit to satisfy indirectly_readable.
    • Val's operator=(Ref ref) needs to return Val& to meet sortable.
    • Ref needs to add operator=(Val) const overload to satisfy indirectly_writable.