如何初始化需要执行计算的const成员?

时间:2016-09-02 12:31:44

标签: c++ class constructor const

我理解为一个班级

class A { 
     const int myint;
  public:
     A (const int yourint);
     A (const std::string yourstring);
};

我可以在初始化列表中初始化myint,如下所示:

A::A (const int yourint) : myint (yourint) {};

但是,如果计算它所需的数据来自字符串并且可能涉及计算,那么从第二个构造函数初始化myint的正确方法是什么?

4 个答案:

答案 0 :(得分:17)

在委托(如果可用,不是必须)构造函数的成员初始化列表中使用函数调用:

A::A(std::string const& yourstring) : A(compute_myint(yourstring)) {};

std::string之前通过const&,而不仅仅是const

compute_myint可以是非成员,静态成员,可能无法从课外访问,无论哪个最有意义。

答案 1 :(得分:8)

如果可以,您可以在这里使用委托构造函数,或者您可以在ctor中进行计算。有关第二个选项,请参阅我的第二个示例你班上的一个例子是:

选项1:委派构造函数:C ++ 11转发

class A { 
     const int myint;
     static int parse_int(const std::string& string) {/*...*/}
  public:
     A (const int yourint) : myint{yourint};
     A (const std::string yourstring) : A{parse_int(yourstring)};
}

顺便说一句,因为parse_int只计算整数,所以它可能是static,这意味着它不需要使用类实例。当然,没有要求,因为函数也可以是一个成员,(非static),虽然static更安全,因为它几乎总能保证对象的构造。

选项2:构造函数计算,非委派

此方法可用于任何C ++版本。

class A { 
     const int myint;
     static int parse_int(const std::string& string) {/*...*/}
  public:
     A (const int yourint) : myint(yourint);
     A (const std::string yourstring) : my_int(parse_int(yourstring));
}

答案 2 :(得分:6)

只需使用会员功能。

请注意,使用static成员函数比非静态成员函数更安全(即不易出错),因为课程并不完整在调用函数时初始化。

class A {
  const int myint;
public:
  A(const int yourint) : myint(yourint) {}
  A(const std::string yourstring) : myint(compute(yourstring)) {}
  static int compute(std::string s) { return (int)s.length(); }
};

答案 3 :(得分:2)

我已经厌倦了这个问题很多次,所以我在一般情况下开发了一个小实用程序来解决它。完整代码如下:

namespace initBlock_detail {
    struct tag { };

    template <class F>
    decltype(auto) operator + (tag, F &&f) {
        return std::forward<F>(f)();
    }
}

#define initBlock \
    initBlock_detail::tag{} + [&]() -> decltype(auto)

使用如下:

int const i = initBlock {
    // Any complex calculation
    // and then return the value
    return foo;
};

See it live on Coliru

该结构类似于Andrei Alexandrescu的ScopeGuard实现,它使用中缀运算符重载和lambda来实现轻量级语法。可以推导出i类型,可以作为参考等。其他有用的功能包括在init-block中放置using namespace声明的可能性。可以使用任何可移动和/或可复制的类型。