使用临时来初始化多个成员

som*_*ver 6 c++ constructor initialization-list

在较旧的C++ 98中,我不相信有任何好方法可以在初始化列表中重用临时结果来初始化对象的多个成员.

在较新版本的C++(11,14,17)中,这有没有改变?

请考虑以下代码:

//
// compileShaders()
//
// Takes a string containing the source code to possibly hundreds of shaders 
// for an effect (In this case, there are only 2 shaders for this effect)
//
// Returns a vector of compiled bytecode for each shader in the effect
//
std::vector<std::string> compileShaders(
    const std::string& sourceCode, 
    const RenderTargetLayout& layout);

//
// class ScaleDownEffect
//
// Scales image to 1/4 in each dimension by using two 1/2 passes
//
class ScaleDownEffect
{
public:
    ScaleDownEffect(const TargetImage& targetImage)
        :   m_renderTarget(targetImage),

            m_firstPassShader(      
                compileShaders(
                    ScaleDownEffectShaderSource, 
                    m_renderTarget.getLayout()
                    )[0], 
                m_renderTarget.getWidth()  / 2, 
                m_renderTarget.getHeight() / 2
                ),

            m_secondPassShader(     
                compileShaders(
                    ScaleDownEffectShaderSource, 
                    m_renderTarget.getLayout()
                    )[1], 
                m_renderTarget.getWidth()  / 4, 
                m_renderTarget.getHeight() / 4
                )
    {
    }

private:
    RenderTarget m_renderTarget;
    Shader m_firstPassShader;
    Shader m_secondPassShader;
};
Run Code Online (Sandbox Code Playgroud)

compileShaders() 是一个非常重量级的电话,我真的不认为在我不需要的时候再打电话两次是个好主意.

注意初始化的三个对象都没有默认ctors,因此在函数体中执行它不是一个真正的选项.

我们怎么想?有没有什么好办法让我这样做,或者我应该切换到智能指针并动态分配我包含的对象?

Jar*_*d42 8

您可以使用自C++ 11以来的委托构造函数:

class ScaleDownEffect
{
     ScaleDownEffect(const TargetImage& targetImage,
                     const std::vector<std::string>& shaders)
     : m_renderTarget(targetImage),
       m_firstPassShader(shaders[0],
                         m_renderTarget.getWidth()  / 2,
                         m_renderTarget.getHeight() / 2),
       m_secondPassShader(shaders[1],
                          m_renderTarget.getWidth() / 4,
                          m_renderTarget.getHeight() / 4)
     {}

public:
    ScaleDownEffect(const TargetImage& targetImage)
        : ScaleDownEffect(targetImage,
                          compileShaders(ScaleDownEffectShaderSource,
                                         targetImage.getLayout())) 
    {
    }

private:
    RenderTarget m_renderTarget;
    Shader m_firstPassShader;
    Shader m_secondPassShader;
};
Run Code Online (Sandbox Code Playgroud)


Arn*_*gel 2

您可以使用嵌套类型:

class ScaleDownEffect
{
    struct Shaders
    {
        explicit Shaders(const std::vector<std::string>& s, unsigned int w, unsigned int h)
            : m_firstPassShader(      
                s[0], 
                w  / 2, 
                h / 2
                ),
              m_secondPassShader(     
                s[1], 
                w  / 4, 
                h / 4
                )
        {}

        Shader m_firstPassShader;
        Shader m_secondPassShader;
    };
    RenderTarget m_renderTarget;
    Shaders m_shaders;

public:
    ScaleDownEffect(const TargetImage& targetImage)
    :   m_renderTarget(targetImage),
    ,   m_shaders(compileShaders(ScaleDownEffectShaderSource,
                                     m_renderTarget.getLayout()),
                  m_renderTarget.getWidth(),
                  m_renderTarget.getHeight())
    {
    }
};
Run Code Online (Sandbox Code Playgroud)

您还可以传递对m_renderTarget嵌套类型的 c'tor 的引用,而不是宽度和高度(我只是假设其类型为unsigned int,顺便说一句)。

有一个缺点,您现在需要访问第一遍着色器,例如m_shaders.m_firstPassShader. 我建议添加(内联)getter 方法,即使它们返回引用,即使它们是私有的,也可以将使用着色器的代码与它们存储方式的更改隔离开来。