C++ 初始化列表功能:调用函数而不初始化成员?

C++ initializer list capabilities: call functions without initializing member?

这是一道关于 C++ 初始化列表语法的问题。

是否可以从初始化列表中调用函数而不将它们作为成员对象构造函数的参数?

下面列出的代码示例是根据工作中的类似情况改写(paracoded?)的。

情况

代码

#include <iostream>

#define LOG { std::cout << __PRETTY_FUNCTION__ << std::endl; }

namespace
{

template <class T>
class SingletonService
{
public:
    static T* Instance() { LOG; return mpT; }
    static void InstallInstance(T* pT) { LOG; mpT = pT; }
    static void DeleteInstance() { if (mpT) delete mpT; }

protected:
    static T* mpT;
};

template <class T>
T* SingletonService<T>::mpT = NULL;

class OneOfMe
{
public:
    OneOfMe() { LOG; };
    virtual ~OneOfMe() { };
};

class Container
{
public:
    Container(OneOfMe* pObj) { LOG; /* Do something with pObj */ }
    virtual ~Container() { }
};

int GenerateNum()
{
    return 42;
}

class Baz
{
public:
    Baz(int num) : mNum(num) { LOG; }
    virtual ~Baz() { }
protected:
    int mNum;
};

class Bar
{
public:
    Bar() : mBaz(GenerateNum()) { LOG; } // Perfectly OK to call function that is argument to member object's non-default ctor.
    virtual ~Bar() { };

protected:
    Baz mBaz;
};

class Foo
{
public:
    Foo()
        : SingletonService<OneOfMe>::InstallInstance(new OneOfMe) // Compile error
        , mContainer(SingletonService<OneOfMe>::Instance()) { }
    virtual ~Foo() { };
protected:
    Container mContainer;
};

}

int main(int argc, char* argv[])
{
    LOG;
    Bar bar;

    SingletonService<OneOfMe>::InstallInstance(new OneOfMe);    // This works.
    Container container(SingletonService<OneOfMe>::Instance()); // And this works.
    SingletonService<OneOfMe>::DeleteInstance();
    return 0;
}

编译错误

>g++ main.cpp
main.cpp: In constructor ‘<unnamed>::Foo::Foo()’:
main.cpp:45: error: expected class-name before ‘(’ token
main.cpp:45: error: no matching function for call to
‘<unnamed>::Container::Container()’
main.cpp:37: note: candidates are:
<unnamed>::Container::Container(<unnamed>::OneOfMe*)
main.cpp:35: note:
<unnamed>::Container::Container(const<unnamed>::Container&)
main.cpp:45: error: expected ‘{’ before ‘(’ token

问题

在语法上是否可以从 class 构造函数的初始化列表 调用函数而不是成员对象的非默认构造函数 的参数?

出于学术好奇心提问。我知道至少还有一个解决方案是在创建包含 class.

之前实例化单例

您可以利用 comma operator.

在你的例子中

class Foo
{
public:
    Foo()
        : mContainer((SingletonService<OneOfMe>::InstallInstance(new OneOfMe),
                      SingletonService<OneOfMe>::Instance()))
    {}
    virtual ~Foo();
protected:
    Container mContainer;
};

请注意两个表达式周围的附加括号,否则它们将被解释为两个而不是一个参数。


解决此特定问题的另一种方法可能是 return 来自 InstallInstance() 的单例,例如

template <class T>
class SingletonService {
public:
    static T *InstallInstance(T *pT) { LOG; return mpT = pT; }
};

然后

class Foo {
public:
    Foo()
        : mContainer(SingletonService<OneOfMe>::InstallInstance(new OneOfMe)) {}
    virtual ~Foo();
protected:
    Container mContainer;
};

Is it possible to call functions from initializer lists without them being arguments to member object constructors?

像这样的东西可能会按预期工作:

void f() {}

struct S {
    S(): i{(f(), 0)} {}
    int i;
};

int main() {
    S s;
}

基本思路是依靠逗号运算符。在这种情况下,函数 returned 的值(如果有)将被丢弃,并且不会用于初始化成员。
当然,我们仍然利用数据成员存在的事实,所以它可能不是您要找的。

如果您想完全摆脱数据成员,您可以使用委托构造函数执行类似的操作,如下例所示:

void f() {}

class S {
    S(int) {}

public:
    S(): S{(f(), 0)} {}
};

int main() {
    S s{};
}

不管调用函数的 return 类型是什么。通过逗号运算符,int 值用作标记​​以将调用分派给正确的编译器,然后将其丢弃。