Search code examples
c++declarationfriendtype-traits

Problem on declaring friend function with type traits in a class


I'm playing around with the singleton pattern in C++, and want to implement an global function that completes the construction of a class. I used std::is_base_of in that function, but that makes it impossible for me to declaring the function in the class.

Here's a short example:

#include <type_traits>
class A {};

template<typename T>
typename std::enable_if_t<std::is_base_of_v<A, T>, T*>
Instance() { return T(); }

template<typename T>
typename std::enable_if_t<!std::is_base_of_v<A, T>, T*>
Instance() { return T(); }

class B : public A {
 protected:
    B();
    friend B* Instance<B>();  // Error
};

The above code will cause "invalid use of incomplete type" using gcc or C2139 using MSVC when instantiating the first function.

So, other than making constructor B::B() to be public, is there any possible way for me to work around with it?


Solution

  • Issue is that during definition of class, the class is still incomplete,

    and std::is_base_of required complete type for Derived, else you have UB.

    If you have access to C++17, you might do:

    template<typename T>
    T* Instance() {
        if constexpr (std::is_base_of_v<A, T>) {
            return nullptr; // Your impl
        } else {
            return nullptr; // Your impl
        }
    }
    
    class B : public A {
     protected:
        B();
        friend B* Instance<B>();
    };
    

    Demo