3

我可以在初始化列表中调用函数吗?请看这段代码:

#include <string>
using namespace std;

class A {
 public:
  A(string path) : s(cfg.getRoot()) {  // before i call getRoot, i need to call cfg.readFile(path.c_str()), is there any methods? (readFile return void)
  }

  private:
   libconfig::Config cfg;
   const libconfig::Setting & s;  // const &, so initalizer list is the only chance for me to init it
}
4

2 回答 2

4

您需要将其包装到仿函数中,例如static成员函数或 lambda(C++11 起):

A(string path) : s([this]() -> const libconfig::Setting & 
                   { cfg.readFile(path.c_str()); return cfg.getRoot(); }
                   () 
                  ) 
{}
于 2020-01-03T03:32:11.860 回答
2

您还可以使用逗号运算符(尽管这对读者来说可能更难理解,也可能不难理解):

A(string path) : s((cfg.readFile(path.c_str()), cfg.getRoot())) {}

内置逗号运算符从左到右求值并丢弃左侧表达式的结果。请注意,双括号是必需的。否则,它将被解析为s的构造函数的两个函数参数。

cfg.readFile(path.c_str())如果 的返回类型有一个重载的逗号运算符(但这非常罕见),这将无法正常工作。在这种情况下,您需要将结果转换void为以丢弃返回值:

A(string path) : s((static_cast<void>(cfg.readFile(path.c_str())), cfg.getRoot())) {}

已经给出了 lambda 方法。如果您使用,您可以避免重复返回类型decltype(auto)

A(string path) : s([this]()->decltype(auto){
    cfg.readFile(path.c_str());
    return cfg.getRoot();
}()) {}

同样,这是一个风格问题,无论您是否更喜欢显式地给出返回类型。

正如@songyuanyao 在下面的评论中所指出的,如果您不指定返回类型或适当的占位符,那么如果cfg.getRoot返回引用就会遇到麻烦,因为默认的 lambda 类型是auto占位符,这将导致临时对象的构造从引用中,然后您将绑定到该引用s并将立即再次被销毁。

于 2020-01-03T03:57:25.080 回答