8

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

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
metalfox
  • 6,301
  • 1
  • 21
  • 43
  • What about anything else that uses `Writeable`? – Caleth Nov 22 '19 at 14:49
  • @Caleth It's been three years an a half, and I don't remember the exact motivation. I assume that I just wanted to know whether or not granting friendship to a concept was possible. By that time there was also the function syntax for concepts, with which it might have been more natural than with the current concept design. – metalfox Nov 22 '19 at 16:29
  • My point was if you friend the concept, you should friend everything that uses the concept, at which point the private thing is essentially public. – Caleth Nov 22 '19 at 16:31

1 Answers1

4

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.

  • 1
    I wonder if down the line they will bind the accessibility check of concepts to the point a concept is used instead of the point where it is defined. The problem arrises when trying to check for construction of an object with private constructor but friendship relation. The construction is a valid statement but the concept declines it. Kinda unintuitive, isn't it? I get it that std::is_constructible should return false, but not std::constructible_from. – rplgn Sep 15 '21 at 12:35