0

I just realized my code base was a bit incoherent with some objects being constructed from strings using a constructor A(const std::string&) and some others being constructed from strings using boost::lexical_cast<A>(const std::string&).

In my understanding, these fulfill the same need but do not behave the same in many ways, exceptions on a badly formatted string and conversions being the first ones that spring to my mind but I'm sure there are also other implications. So my questions is: What should I be using and why?


Edit: as per @hetepeperfan's comment, I'm transforming the std::string arguments in const std::string&, which is what I meant in the first place

4

2 回答 2

2

我可以想象一个类InputFile(类似于std::ifstream),它接受代表文件系统中文件路径的字符串:

InputFile f("/dir/file.txt");
use(f);

在这里使用boost::lexical_cast至少会很奇怪。

我想这个观察可以这样概括:如果你的类型A代表一个与 兼容std::string或可转换为的值std::string,你有两个选择。但是,如果您在接口中公开一个构造函数,该构造函数将一个类型的非可选参数std::string用于转换值以外的其他目的,则仅使用构造函数才有意义(并且此构造函数应该是explicit)。

于 2013-05-27T08:53:00.677 回答
1

据我了解,这些满足相同的需求 [...]

它们不能满足相同的需求。用于创建对象的接口应该始终最好地表达创建对象背后的语义。词法转换是将字符串值转换(重新解释)到对象实例。如果你的对象是用一个字符串值构造的,而不是字符串中的值构造的,那么使用 boost::lexical_cast 只会令人困惑。

[...] 但在许多方面表现不一样,格式错误的字符串和转换是我首先想到的例外,但我确信还有其他含义。所以我的问题是:我应该使用什么以及为什么?

如果您的对象可以从任何字符串值构造(即不依赖于字符串中的值,而只是在内部复制字符串),那么您应该将它直接传递给构造函数。

如果将字符串值传递给构造函数意味着您可以创建具有无效值的实例,则应使用工厂函数(在实例化对象之前引发错误)或 [不太喜欢] 在构造函数中添加异常验证(不太理想) ,不太干净,在大多数情况下设计更差)。

如果您的对象实例建模了可以从字符串中的值的解释(“强制转换”)中创建的值/类型特化,那么您应该支持通过boost::lexical_cast<YourClass>(const std::string&).

编辑:如果您构造一个具有名称的对象(例如某个记录器对象),但记录器的功能/值不取决于名称是什么(对象记录相同,只是名称不同),那么您不应定义基于 lexical_cast 的实现(因为名称不会更改记录器的功能)。

相反,如果您创建一个对象,其值/功能取决于字符串中的值(解析字符串中的值并将其转换为“复数”类实例),那么实例的行为取决于string (lexical_cast<ComplexNo>("(0 + 0i)")将返回不能被除的东西,而不是 what lexical_cast<ComplexNo>("(1 + 0i)"))。在这种情况下(一个值对象取决于字符串中的内容),您应该支持 lexical_cast。

基本上,为值对象提供基于 lexical_cast 的实现。

于 2013-05-27T10:27:45.977 回答