在 class 中声明具有类型特征的友元函数时出现问题

Problem on declaring friend function with type traits in a class

我正在研究 C++ 中的单例模式,想实现一个全局函数来完成 class 的构造。我在该函数中使用了 std::is_base_of,但这使我无法在 class.

中声明该函数

这是一个简短的例子:

#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
};

以上代码在实例化第一个函数时使用 gcc 或 C2139 使用 MSVC 将导致“不完整类型的无效使用”。

那么,除了让构造函数 B::B() 成为 public 之外,我还有什么办法可以解决这个问题吗?

看来只能用静态成员函数(如B::Instance())来实现单例模式,用构造函数来完成具体的功能...

代码:

#include <type_traits>
class A {
 protected:
    A() {
       // Do something special here
    }
};

class B : public A {
 protected:
    B();

 public:
    static B* Instance() {
        static B* b = new B();
        return b;
    }
};

问题是在定义 class 期间,class 仍然 不完整

std::is_base_of 需要 Derived 的完整类型,否则你有 UB。

如果您可以访问 C++17,您可能会:

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

您可以使用模板仿函数构建目标 class 的对象。此仿函数必须是目标 class 的友元。请参阅下面的示例。

#include <type_traits>
#include <tuple>

class A {};

template <typename T>
struct Instance_t
{    
    T* operator () () const
    {
        if constexpr (std::is_base_of_v<A, T>)
        {
            return new T();
        }
        else
        {
            return nullptr;
        }
    }
};
template <typename T>
constexpr Instance_t<T> Instance{};

class B : public A {
 protected:
    B()
    {}
    
    template <typename T> friend struct Instance_t;
};

int main()
{
    auto b=Instance<B>();
    std::ignore=b;
    return 0;
}

检查Demo