Search code examples
c++friendc++17c++-concepts

C++ concept with friend-like access


Is it possible to make this code work as I'd like? I.e. to allow the concept to have access to a private member funcion?

template <typename T>
concept bool Writeable()
  { return requires (T x,std::ostream os) { { x.Write(os) } -> void }; }

template <Writeable T>
void Write(std::ostream &os,const T &x) { x.Write(os); }

class TT
{
private:
  void Write(std::ostream &os) const { os << "foo"; }

//friend concept bool Writeable<TT>();
friend void ::Write<TT>(std::ostream &,const TT &);
};

Thanks


Solution

  • No. Concepts explicitly are not allowed to be friends.

    n4377 7.1.7/2

    Every concept definition is implicitly defined to be a constexpr declaration (7.1.5). A concept definition shall not be declared with the thread_local, inline, friend, or constexpr specifiers, nor shall a concept definition have associated constraints (14.10.2).

    We can reduce it to this example to show that the access really is the problem:

    template <typename T>
    concept bool Fooable = requires (T t) { { t.f() } -> void };
    
    struct Foo
    {
    private:
        void f() {}
    };
    
    
    int main()
    {
        static_assert(Fooable<Foo>, "Fails if private");
    }
    

    You can however use a level of indirection, something like this:

    template <typename T>
    void bar(T t) { t.f(); }
    
    template <typename T>
    concept bool FooableFriend = requires(T t) { { bar(t) } -> void };
    
    struct Foo
    {
    private:
        void f() {}
    
        template<typename T>
        friend void bar(T t);
    };
    
    
    int main()
    {
        static_assert(FooableFriend<Foo>, "");
    }
    

    Live demo incorporating your example

    Which works. Concepts are pretty early, so I imagine down the line that they might lift the friend restriction just as proposals have lifted restrictions for C++11/14 features in the past.