c++clanglanguage-lawyerlibc++standards-compliance

May the compiler add extra defaulted template parameters to the std templates?


Consider the following code:

#include <memory>

class A {
protected:
    ~A() = default;

    friend void std::destroy_at<A>(A*); // libstdc++ ok, but libc++ failed.

public:
    void f() {
        std::destroy_at(this);
    }
};

int main() {
}

See online demo.

Note that for the code above, libstdc++ is ok, while libc++ is not.

The root cause is: libc++ implements std::destroy_at as follows:

template<typename T, enable_if_t<!is_array_v<T>, int> = 0>
void destroy_at(T*) { ... }

However, the C++ standard actually defines std::destroy_at as follows:

template<typename T>
void destroy_at(T*) { ... }

May the compiler add extra defaulted template parameters to the std templates? Is it conforming to the standard?


Solution

  • By implementing a simple destroy_at locally, one can see that friendship is granted:

    template<typename T, std::enable_if_t<!std::is_array_v<T>, int> = 0>
    void destroy_at(T* loc) { loc->~T(); }
    

    link

    The problem in this case with libc++ is that the destructor is not directly called from std::destroy_at. Instead, std::destroy_at calls a helper std::__destroy_at. The helper is not a friend.