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

Posted

技术标签:

【中文标题】C++ 初始化器列表功能:调用函数而不初始化成员?【英文标题】:C++ initializer list capabilities: call functions without initializing member? 【发布时间】:2016-11-02 20:46:55 【问题描述】:

这是一个关于 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

问题

在语法上是否可以从类构造函数的初始值设定项列表中调用函数而不是成员对象的非默认构造函数的参数

这个问题是为了学术好奇心。我知道至少另一种解决方案是在创建包含类之前实例化单例。

【问题讨论】:

【参考方案1】:

您可以使用comma operator。

在你的例子中

class Foo

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

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


解决这个特定问题的另一种方法可能是从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;
;

【讨论】:

【参考方案2】:

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

这样的事情可能会按预期工作:

void f() 

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

int main() 
    S s;

基本思想是依靠逗号操作符。在这种情况下,函数返回的值(如果有)将被丢弃,不用于初始化成员。 当然,我们仍然利用数据成员存在这一事实,因此它可能不是您要查找的内容。

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

void f() 

class S 
    S(int) 

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

int main() 
    S s;

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

【讨论】:

谢谢;我在你之前得到了 Olaf 的答案,但也感谢你将我介绍给逗号运算符。

以上是关于C++ 初始化器列表功能:调用函数而不初始化成员?的主要内容,如果未能解决你的问题,请参考以下文章

是否可以在 C++ 的成员初始化程序列表中初始化数组?

可以在不调用 memset 的情况下从构造函数初始化器列表中将成员结构设为零吗?

在 C++ 中定义对象而不调用其构造函数

C++构造函数的初始化列表

[ C++ ] 类与对象(下) 初始化列表,友元,static成员,内部类

C++特殊成员