可选择下降嵌套结构

时间:2017-07-05 22:21:30

标签: c++ templates nested

假设存在类模板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

3 个答案:

答案 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;

Demo

答案 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可以帮助这样做),或者你可以可能会使用动态演员来完成它。