Search code examples
c++c++11gccclangaccess-modifiers

is_constructible and is_destructible unaffected by friend declarations


Clang and GCC appear not to honor friend declarations when evaluating std::is_constructible and std::is_destructible.

Regarding `is_constructible, cppreference.com says:

Access checks are performed as if from a context unrelated to T and any of the types in Args. Only the validity of the immediate context of the variable definition is considered.

(The site doesn't explain how is_destructible deals with access checks, but access modifiers do affect the behavior of is_destructible in general, so I'd expect it to work the same way as is_constructible.)

Therefore, it seems to me that this code should not compile, since in the immediate context of the check the constructor and destructor are available, as evidenced by the local variable instantiation:

class Private
{
    Private() {}
    ~Private() {}

    friend class Friend;
};

class Friend
{
    public:
        Friend()
        {
            // Both of these should fire, but they do not.
            static_assert(
                !std::is_constructible<Private>::value,
                "the constructor is public");
            static_assert(
                !std::is_destructible<Private>::value,
                "the destructor is public");
            // There is no error here.
            Private p;
        }
};

...but Coliru compiles it without error (using either GCC or Clang).

Is this a bug (or at least a nonconformity) in both compilers, or is cppreference.com misrepresenting the standard, or am I misunderstanding cppreference.com's statement?


Solution

  • This is exactly what

    Access checks are performed as if from a context unrelated to T and any of the types in Args.

    says. "A friend of T" is by definition not "unrelated to T".

    "immediate context" is a term of art, but in any event the sentence is talking about the immediate context of the hypothetical variable definition, not the use of is_constructible.

    It would be madness to make the is_constructible check context-dependent; that would mean that the same type, is_constructible<T, Args...>, has different base classes in different contexts.