如果对象是堆栈创建的(包括继承的类型),是否可以发出编译错误

Is it possible to issue compile error if object is stack created (including inherited types)?

本文关键字:是否 错误 编译 类型 堆栈 对象 创建 继承 包括 如果      更新时间:2023-10-16

基本上,我希望通过工厂方法创建所有子类型(我有一个高大的域层次结构,其中包含大约 200+ 个类)。

对于new,这不是问题,因为这可以在A中被覆盖(使new私有)。

class A{
protected:
  A();
public:
  template<class T, typename... ARGUMENTS>
  static T* create(ARGUMENTS&&... arguments);
};
class B : public A {
public:
  B();
};
void test() {
  B b;//compile error wanted here - but as a consequence of inheriting A
}

这里 A 是"库/框架"类,而 B 是"用户创建的类"。在 B 上要求 typedef 或类似的东西可能是可以的。

更新:我在 A 上添加了"创建"功能,我打算用于创建对象。

您可以在构造

A中要求仅在A::create正文中传递的令牌

#include <utility>
class A{
private:
  struct create_token
  { 
    create_token(const create_token &) = delete; 
    create_token& operator=(const create_token &) = delete; 
    create_token(create_token &&) = default; 
    create_token& operator=(create_token &&) = default; 
  };
protected:
  A(create_token) {}
public:
  template<class T, typename... ARGUMENTS>
  static T* create(ARGUMENTS&&... arguments)
  {
    // Whatever creation mechanism here
    return new T(create_token{}, std::forward<ARGUMENTS>(arguments)...);
  }
};
class B : public A {
public:
  template <typename Token> // Can't name A::create_token, it is private
  B(Token tok) : A(std::move(tok)) {}
  B(){} // Will always lack a `create_token`
};
int main() {
  B b;//compile error wanted here - but as a consequence of inheriting A
  B* b = A::create<B>();
}

现场观看

这是另一种依赖于检查派生类构造函数是否私有的方法。但老实说,我更喜欢@Caleth给出的解决方案

#include <type_traits>
#include <iostream>
#include <type_traits>

template<typename T, typename... Args>
struct constructor_tag{};

class A{
protected:

    template<typename T, typename... Args>
    A(constructor_tag<T, Args...>) {
        static_assert(!std::is_constructible_v<T, Args...>, "CONSTRUCTOR MUST NOT BE PUBLIC");
    };

public:
    template<class T, typename... ARGUMENTS>
    static T* create(ARGUMENTS&&... arguments) {
        return new T(std::forward<ARGUMENTS>(arguments)...);
    }
};
class B : public A {
    friend class A;
    B() : A(constructor_tag<B>{}) {}
public:
};
class C : public A {
    friend class A;
    C () : A(constructor_tag<C>{}) {}
    C(int) : A(constructor_tag<C, int>{}) {}
public:
};

// Following class will not compile because the constructor is public
//class D : public A {
//    friend class A;
//
//public:
//    D () : A(constructor_tag<D>{}) {}
//
//};
void test() {
    // B b; //calling a private constructor of class 'B'
    // C c(5);//calling a private constructor of class 'A'
    A::create<B>();
    A::create<C>(5);
    A::create<C>();
}
int main() {

    test();
}