如果对象是堆栈创建的(包括继承类型),是否可能发出编译错误?
Is it possible to issue compile error if object is stack created (including inherited types)?
基本上我希望所有子类型都通过工厂方法创建(我有一个很高的域层次结构,大约有 200 多个 classes)。
对于 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是"library/framework"class。而 B 是 "user created class"。在 B 上要求 typedef 或类似的东西可能没问题。
更新:我在 A 上添加了 'create' 函数,我打算将其用于创建对象。
您可以在 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>();
}
这是另一种方法,它依赖于检查派生的 class 构造函数是否私有。但老实说,我更喜欢@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();
}
基本上我希望所有子类型都通过工厂方法创建(我有一个很高的域层次结构,大约有 200 多个 classes)。
对于 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是"library/framework"class。而 B 是 "user created class"。在 B 上要求 typedef 或类似的东西可能没问题。
更新:我在 A 上添加了 'create' 函数,我打算将其用于创建对象。
您可以在 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>();
}
这是另一种方法,它依赖于检查派生的 class 构造函数是否私有。但老实说,我更喜欢@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();
}