问题
Introduction
Let's introduce this simple example:
#include <cmath>
class X
{
public: // Members
/// A ^ B + A
int A;
/// A ^ B + B
int B;
public: // Specials
X(
const int & A,
const int & B
)
: A(A)
, B(B)
{
const auto Pow = static_cast<int>(std::pow(A, B));
this->A += Pow;
this->B += Pow;
}
};
Trivia
- Introduced class has two member variables:
AandB. - They take value of
A ^ B + AandA ^ B + B, respectively. - Both of them shares common complex initialization code (let's assume
std::powis complex).
Problem
I'd like to make both A and B members const.
Question
How to do that without repeating complex initialization (ie avoid calling std::pow twice)?
What I've tried
#include <cmath>
class X
{
public: // Members
/// A ^ B + A
const int A;
/// A ^ B + B
const int B;
public: // Helpers
struct Init
{
public: // Members
int A;
int B;
public: // Specials
Init(
const int & A,
const int & B
)
: A(A)
, B(B)
{
const auto Pow = static_cast<int>(std::pow(A, B));
this->A += Pow;
this->B += Pow;
}
};
public: // Specials
X(
const Init& Init
)
: A(Init.A)
, B(Init.B)
{};
X(
const int & A,
const int & B
)
: X(Init(
A,
B
))
{};
};
- Create
struct Initthat takes role of past version of classX. - Make
Xmembersconstwhile keepInitmembers nonconst. - Use constructor delegation to redirect constructor arguments to
Init. - Move non
constmember variables fromInittoXand make themconst.- Note there is no
std::moveasintis TriviallyCopyable.
- Note there is no
However, my solution seems overcomplicated. Any help would be appreciated.
No goals
- Make another
Xmember variable that will store common code result (iestd::pow). - Add another level of indirection outside
Xclass (eg introduce base class forX).
Note
Solutions can use newer versions of C++ than C++11.
回答1:
Using a delegating constructor is a good option for such cases.
class X
{
public: // Members
/// A ^ B + A
const int A;
/// A ^ B + B
const int B;
public:
X(int a, int b) : X(a, b, func1(a, b)) {}
private:
X(int a, int b, int c) : A(func2(a, b, c)), B(func3(a, b, c)) {}
static int func1(int a, int b) { return std::pow(a,b); }
static int func2(int a, int b, int c) { return (a + c); }
static int func3(int a, int b, int c) { return (b + c); }
};
The logic/computation in func1, func2, and func3 can be as simple or as complex as you need.
回答2:
You can solve this by using a factory function. You make the constructor of X private and then use a friend/static function to get objects of X. Then you can do the complex code in the body of the function and then pass those values to the constructor of X. That would look something like
class X
{
public:
const int A;
const int B;
friend X make_X(int a, int b)
{
// do complex stuff
return X(complex_result1, complex_result2);
}
// or
static X make(int a, int b)
{
// do complex stuff
return X(complex_result1, complex_result2);
}
private:
X(const int A, const int B) : A(A), B(B) {}
};
and would be used like
X foo = make_x(a, b);
//or
X foo = X::make(a, b);
来源:https://stackoverflow.com/questions/55382549/how-to-initialize-multiple-constant-member-variables-that-shares-complex-initial