更简洁代码的嵌套命名空间
Nested namespace for cleaner code
我目前正在编写一个适配器,以在两个框架 A <-> B 之间转换类型。我对名称有点不满意,因为在我看来它们变得很长且难以阅读。然后我决定以一种非常嵌套的方式使用命名空间,我在其他地方很少见到。
旧:
TypeA mylib::cvtToAtype(TypeB) {}
TypeB mylib::cvtToBtype(TypeA) {}
新:
TypeA mylib::cvt::to_a::type(TypeB) {}
TypeB mylib::cvt::to_b::type(TypeA) {}
您认为这是一种很好的风格还是认为有严重的缺点?我认为它看起来很干净,但是如果有人决定 "use namespaces",它可能会被滥用。那么 type 实际上并不是一个唯一的名称来标识函数在做什么。此外,名为 "cvt" 的命名空间也可能不是超级唯一的。
你怎么看?
所以,您开始于:
TypeA mylib::cvtToAtype(TypeB) {}
TypeB mylib::cvtToBtype(TypeA) {}
您提出的问题:函数名称 "getting quite long and unreadable"。你提议:
mylib::cvt::to_a::type
首先,"cvt" 不会被您的代码的 readers/maintainers 轻松识别为 "convert"。尾随 ::type
对我来说似乎毫无意义。任何称为 "to_" 的东西都可以预期是转换,所以我看不到 ::cvt::
级别的要点。
无论其价值如何,一些替代方案...
构造函数
您可以考虑创建构造函数 [explicit] TypeA::TypeA(TypeB)
和 [explicit] TypeB::TypeB(TypeA)
因此客户端用法很简单:
TypeA a{b};
functionThatWantsB(TypeB{a});
Cast/conversion 模板
如果您想将函数与 TypeA/B 类 分开,具有特殊化的 "cast" 样式模板是一个不错的选择:
template <typename TypeTo, typename TypeFrom>
TypeTo convert(const TypeFrom&);
template <>
TypeB convert<TypeB, TypeA>(const TypeA& a) { return TypeB{...}; }
template <>
TypeA convert<TypeA, TypeB>(const TypeB& a) { return TypeA{...}; }
客户端用法就是熟悉的转换符号:例如convert<TypeB>(a)
。这比 cvtToAtype
强大得多,因为如果目标类型是抽象的——模板中的参数,来自 using
或 typedef
的别名——你仍然可以转换。
知道目标类型,因为它是一个函数参数
另一种选择是使用转换为类型的函数参数,这样调用者就不必将其作为转换函数名称或模板参数的一部分键入:
TypeA& loadFrom(TypeA&, const TypeB&) { ... }
TypeB& loadFrom(TypeB&, const TypeA&) { ... }
重载的编译时多态性的这种使用意味着每次涉及的变量在支持的类型之间发生变化时不需要更新转换代码。
我目前正在编写一个适配器,以在两个框架 A <-> B 之间转换类型。我对名称有点不满意,因为在我看来它们变得很长且难以阅读。然后我决定以一种非常嵌套的方式使用命名空间,我在其他地方很少见到。
旧:
TypeA mylib::cvtToAtype(TypeB) {}
TypeB mylib::cvtToBtype(TypeA) {}
新:
TypeA mylib::cvt::to_a::type(TypeB) {}
TypeB mylib::cvt::to_b::type(TypeA) {}
您认为这是一种很好的风格还是认为有严重的缺点?我认为它看起来很干净,但是如果有人决定 "use namespaces",它可能会被滥用。那么 type 实际上并不是一个唯一的名称来标识函数在做什么。此外,名为 "cvt" 的命名空间也可能不是超级唯一的。
你怎么看?
所以,您开始于:
TypeA mylib::cvtToAtype(TypeB) {}
TypeB mylib::cvtToBtype(TypeA) {}
您提出的问题:函数名称 "getting quite long and unreadable"。你提议:
mylib::cvt::to_a::type
首先,"cvt" 不会被您的代码的 readers/maintainers 轻松识别为 "convert"。尾随 ::type
对我来说似乎毫无意义。任何称为 "to_" 的东西都可以预期是转换,所以我看不到 ::cvt::
级别的要点。
无论其价值如何,一些替代方案...
构造函数
您可以考虑创建构造函数 [explicit] TypeA::TypeA(TypeB)
和 [explicit] TypeB::TypeB(TypeA)
因此客户端用法很简单:
TypeA a{b};
functionThatWantsB(TypeB{a});
Cast/conversion 模板
如果您想将函数与 TypeA/B 类 分开,具有特殊化的 "cast" 样式模板是一个不错的选择:
template <typename TypeTo, typename TypeFrom>
TypeTo convert(const TypeFrom&);
template <>
TypeB convert<TypeB, TypeA>(const TypeA& a) { return TypeB{...}; }
template <>
TypeA convert<TypeA, TypeB>(const TypeB& a) { return TypeA{...}; }
客户端用法就是熟悉的转换符号:例如convert<TypeB>(a)
。这比 cvtToAtype
强大得多,因为如果目标类型是抽象的——模板中的参数,来自 using
或 typedef
的别名——你仍然可以转换。
知道目标类型,因为它是一个函数参数
另一种选择是使用转换为类型的函数参数,这样调用者就不必将其作为转换函数名称或模板参数的一部分键入:
TypeA& loadFrom(TypeA&, const TypeB&) { ... }
TypeB& loadFrom(TypeB&, const TypeA&) { ... }
重载的编译时多态性的这种使用意味着每次涉及的变量在支持的类型之间发生变化时不需要更新转换代码。