具有以下课程:
class Foo {
public:
Foo() : m_data{std::nullopt} {} // this is fine (not having m_data set),
// but only at the beginnig of objects lifetime
Foo(Bar data) : m_data{data} {}
void setData(Bar newData);
Bar getData() const;
void doJob() const; // requires m_data to be set (not std::nullopt)
void doOtherJob() const; // does not require m_data to be set.
/*...*/
private:
std::optional<Bar> m_data;
在开始时,有可能没有设置m_data
,而是仅设置到第一个setData()
调用点,然后m_data
永远不会回到空状态( std::nullopt
)
我的问题是,如果这些对象被标记为Foo
,我可以以某种方式告诉编译器从不允许使用第一个构造函数(默认值:Foo()
)构造const
类型的对象
这样就不会有这种类型的代码了:
const Foo x; // without const totally fine
// x.setData( Bar{} ); // but with it, setData cannot be called
x.doJob(); // which makes that call a 100% throw error
// and in general, whole object is less usefull now
// because it is constructed only partially,
// and cannot be finished
要通过编译阶段吗?
最终效果应如下所示:
Bar data = getSomeData();
Foo a; // fine
Foo b{data}; // fine
const Foo c; // error, this type will never be usefull / is artificially limited,
// no logical reason to make it const
const Foo d{data}; // fine
有什么方法可以在编译时获取有关给定新对象的const'ness
的信息(在对象类构造代码或定义中),以便我可以使用SFINAE或其他方法来拆分,区分不同的构造例程const
和not-const
对象?
我希望在编译时完成。
能够只写类似这样的东西会很好:
class Foo{
public:
// both can still mutate everything
Foo() { /*...*/ } // but this one cant be called by const objects
Foo(Bar data) const { /*...*/ } // and this one can
};
它不会尝试使this
指针const Foo*
而是只假装它,所以const
对象不能称其为第一个“方法”,但这是我不允许的知道并检查了这一点。
(类型Bar
不能设置为某种默认值,即null值。它可以是,也可以不,我想保持这种状态)
我也不知道为什么不能用const
来标记构造函数,因为(我认为)那时所有可以部分构造对象的类都没有问题,但是仍然必须完全实现才能正常工作或发挥其潜力。
我找不到其他遇到相同问题的程序员,所以我提出了扩展代码示例来检查这是否真的是一个问题(使用不同的创建const
对象的方法)还是我只是在做一些事情错误的方式。我是否缺少任何设计模式,编程风格等,这些问题就不存在了?
我知道在run-time
和const
对象之间没有区别,但这不是重点。我相信可以在not-const
处解决此问题,我只是不知道如何告诉编译器我的想法。
修改:
用compile-time
创建对象很有用(仅使用其功能的一部分),但是只有在以后它会完成需要Foo()
的主要工作时。
答案 0 :(得分:2)
否,在构造函数中无法知道对象是const还是非const。因此,您所需的功能无法实现。您有两种选择:
doJob
是默认构造对象的错误,那么为什么不禁止这种无效状态呢?const Foo c;
无用的事实,但是编译器不会告诉程序员。如果程序员测试他们编写的代码,那么他们应该很快就发现这一点。从类的文档中,无用也应该变得很清楚。