C ++初始化程序列表功能:调用函数而不初始化成员吗? [英] C++ initializer list capabilities: call functions without initializing member?

查看:128
本文介绍了C ++初始化程序列表功能:调用函数而不初始化成员吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是有关C ++初始化列表的语法的问题.

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

下面列出的代码示例是从工作中的类似情况解释而来的.

情况

  • 成员变量将指向单例的指针作为构造函数 争论.
  • 成员变量由其包含类的构造函数中的初始化程序列表构造.
  • 在构造包含类之前尚未创建单例.

代码

#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 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;
};

This is a question on the syntax of C++ initializer lists.

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

Code example listed below is paraphrased (paracoded?) from a similar situation at work.

The Situation

  • A member variable takes a pointer to a singleton as constructor argument.
  • The member variable is constructed by initializer list in its containing class' constructor.
  • The singleton has not been created prior to the containing class being constructed.

The Code

#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;
}

The compile error

>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

The Question

Is it syntactically possible to call a function from a class constructor's initializer list without being an argument to a member object's non-default constructor?

The question is for academic curiosity. I know at least one other solutions is to instantiate the singleton before creating the containing class.

解决方案

You can utilize the comma operator.

In your example

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

Note the additional parentheses around the two expressions, otherwise these would be interpreted as two instead of one parameter.


Another approach to this particular problem could be to return the singleton from InstallInstance() as well, e.g.

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

and then

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

这篇关于C ++初始化程序列表功能:调用函数而不初始化成员吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆