假设存在类模板Optional
:
template <class T>
class Optional
{
public:
...
bool isPresent(void) const {...}
const T& value(void) {...} // throws if !isPresent()
...
};
此外,还定义了一些嵌套Optional
字段的结构:
struct A;
struct B;
struct C;
struct D;
struct A
{
Optional<B> b1_;
int i_;
};
struct B
{
Optional<C> c1_;
int j_;
};
struct C
{
Optional<D> d1_;
int k_;
};
struct D
{
int l_;
int m_;
int n_;
};
我正在寻找一种编程习惯用法,它提供以下行为,而不是丑陋。
int get_l_OrDefault(const A& a, int def)
{
if (!a.b_.isPresent()) return def;
else if (!a.b_.value().c_.isPresent()) return def;
else if (!a.b_.value().c_.value().d_.isPresent()) return def;
else return a.b_.value().c_.value().d_.value().l_;
}
给定一个A a;
,我可以定义一些东西来表示非可选叶子字段的路径和默认值吗?
getValueOrDefault(a.b.j_, 0);
getValueOrDefault(a.b.c.k_, 0);
... etc
答案 0 :(得分:0)
您可以执行类似
的操作template <typename Class, typename Def, typename M>
Def getValueOrDefault(const Class& c, Def, M m)
{
return c.*m;
}
template <typename Class, typename Def, typename M, typename ... Ms>
Def getValueOrDefault(const Class& c, Def def, M m, Ms... ms)
{
if (c.*m) {
return getValueOrDefault(*(c.*m), def, ms...);
} else {
return def;
}
}
使用方法:
std::cout << getValueOrDefault(a, 0, &A::b, &B::j) << std::endl;
std::cout << getValueOrDefault(a, 0, &A::b, &B::c, &C::k) << std::endl;
答案 1 :(得分:0)
这需要绑定。
Bind从a到b或b的可选项中选择a和a函数的可选项,并返回b的可选项。
假设我们有一个命名运算符->*bind*
,它理解指向成员的指针。然后
auto op_l = a->*bind*&A::b1_->*bind*&B::c1_->*bind*&C::d1_->*bind*&D::l_;
return value_or(op_l,def);
(值或取可选和默认值)。
答案 2 :(得分:0)
你需要递归来做这件事。例如,如果您可以为A,B,C,结构体提供相同的基类,则可以使用以下内容:
struct Presentable <T> {
Optional<T> opt;
virtual int getIntValue(int def) {
if (opt.isPresent())
return opt.getValue().getIntValue(def);
else
return def;
}
};
struct A : public Presentable<B>) {
int i_;
};
...
struct D : Presentable <F> {
int getIntValue(int) {return l_;}
}
现在你可以从链的末尾或'def'获得你的价值。
这只是可能的变体之一,但无论如何你需要一些基类,或者你可以使用指针在结构之间创建父子关系(Optional class可以帮助这样做),或者你可以可能会使用动态演员来完成它。