将2个未定义类型的参数传递给构造函数(预期为2)

时间:2015-06-26 00:42:05

标签: function boost parameters

我有一个构造函数,其中我想传递前2个参数: ID3D11ShaderResourceView * 作为稳定下载的纹理 OR const CHAR * 作为文件下载这个纹理并将其分配给类ID3D11ShaderResourceView *成员(按需发布以下版本),但我无法理解我应该如何正确地做到这一点。它看起来像这样:

class {button
public
button() {};    
button(data1 (or texture or filname), data2 (or texture or filname), rest data....);
...
~button();
}

所以我试过了:

  • 模板但失败了,可能是缺乏知识的原因,模板 定义一种类型,而我需要选择2. Varradic模板,或者我没有把它们弄好但是当我需要先区分2时,它们意味着不确定的变量数量。
  • 联盟,但它与类变量集冲突 - 表示无法将const char [amount]与const char *匹配,并且联合不能与std :: string一起使用。
  • 尝试使用typeid.name()进行void *,但它始终显示“void *”

我不想重载构造函数,因为这将创建其中4个,它们几乎不同。你认为boost :: variant在这种情况下对我有帮助吗?是否有任何平滑有效的方法来构建这种构造函数?我的c ++知识是初级的,对不起,如果它是一个重复的主题,在创建它的同时阅读它给我的建议,但似乎没有发现任何类似的东西,谢谢:)

更新 应用boost :: any,得到下一个结果:

class button : public frame {
public:
    button() {};
    button(boost::any                 _texture,
           boost::any                 _hover_texture,
           ...
    };

if (_texture.type() == typeid(ID3D11ShaderResourceView*)) texture = boost::any_cast<ID3D11ShaderResourceView*>(_texture); 
if (_texture.type() == typeid(const char*)) 
{
if ( FAILED(D3DX11CreateShaderResourceViewFromFile(gvDevice,boost::any_cast<const char*>(_texture), NULL, NULL, &texture, NULL )) )
mboxout( "loading texture failed.", "UI texture load error", true );
};

if (_hover_texture.type() == typeid(ID3D11ShaderResourceView*)) hover_texture = boost::any_cast<ID3D11ShaderResourceView*>(_hover_texture); 
if (_hover_texture.type() == typeid(const char*))
{
if ( FAILED(D3DX11CreateShaderResourceViewFromFile(gvDevice,  boost::any_cast<const char*>(_hover_texture), NULL, NULL, &hover_texture,    NULL )) )
mboxout( "loading texture failed.", "UI texture load error", true );
};

这是唯一可能的决定,因为这对我来说似乎很尴尬吗?谢谢:))

1 个答案:

答案 0 :(得分:0)

As always, when you have combinatoric explosion/tedious repetition, refactor your code into reusable units.

In this case, your constructor could be just

template <typename T1, typename T2>
button(T1 const& texture, T2 const& hover_texture)
    : _texture(load(texture)), 
      _hover_texture(load(hover_texture))
{
};

And all the loading logic would be inside... you guess it the load function. A sample implementation of that:

static ID3D11ShaderResourceView* load(ID3D11ShaderResourceView* v){
    return v; // just return the resources passed in
}

static ID3D11ShaderResourceView* load(char const* fname) { 
    ID3D11ShaderResourceView* p = NULL;
    if (FAILED(D3DX11CreateShaderResourceViewFromFile(gvDevice, fname, NULL, NULL, &p, NULL)))
        throw std::runtime_error(std::string("loading texture failed (") + fname + ")");

    return p;
}

Note: while we were at it we separated UI from business logic. You do not want to display messageboxes from inside constructors. Ever. You just want to notify the caller of the problem and the caller decides what to do (use another resource, try a different path, retry a download, write a warning message to the log, shut down etc.)

Full Demo

Live On Coliru

#include <iostream>
#include <stdexcept>

///////////////////////////////////////////////////////
// mocking ID3D*
    struct ID3D11ShaderResourceView;
    enum ERROR_CODE { ERR_OK };
#define FAILED(e) (ERR_OK != (e))
    static int gvDevice = 42;
    ERROR_CODE D3DX11CreateShaderResourceViewFromFile(int, char const* fname, void*, void*, ID3D11ShaderResourceView**, void*) {
        std::cout << "Loaded from " << fname << "\n";
        return ERR_OK;
    }
//
///////////////////////////////////////////////////////

struct frame{ virtual ~frame() = default; };

class button : public frame {
public:
    button() {};

    template <typename T1, typename T2>
    button(T1 const& texture, T2 const& hover_texture)
        : _texture(load(texture)), 
          _hover_texture(load(hover_texture))
    {
    };

private:
    // TODO Rule-Of-Three constructor/destructorl 
    // SUGGEST: Rule-Of-Zero using shared pointers instead
    ID3D11ShaderResourceView* _texture;
    ID3D11ShaderResourceView* _hover_texture;

    static ID3D11ShaderResourceView* load(ID3D11ShaderResourceView* v) { return v; }
    static ID3D11ShaderResourceView* load(char const* fname) { 
        ID3D11ShaderResourceView* p = NULL;
        if (FAILED(D3DX11CreateShaderResourceViewFromFile(gvDevice, fname, NULL, NULL, &p, NULL)))
            throw std::runtime_error(std::string("loading texture failed (") + fname + ")");

        return p;
    }
};

#include <cassert>

int main() {
    ID3D11ShaderResourceView* default_texture = NULL;
    assert(!FAILED( D3DX11CreateShaderResourceViewFromFile(gvDevice, "default_texture.bin", NULL, NULL, &default_texture, NULL)));

    try {

        button button1("t1.bin",        "hover1.bin");
        button button2(default_texture, "hover2.bin");
        button button3("t3.bin",        default_texture);
        button button4(default_texture, default_texture);

    } catch(std::exception const& e) {
        std::cout << "Oops: " << e.what() << "\n";
    }
}

Prints:

Loaded from default_texture.bin
Loaded from t1.bin
Loaded from hover1.bin
Loaded from hover2.bin
Loaded from t3.bin

There's still a lot to be improved (see the comments, e.g.) but this is a start.