Initializing array through explicit constructor

佐手、 提交于 2019-12-08 11:40:48

问题


I'm writing a class that has an explicit constructor taking a const char* argument. For the intents and purposes of this question it looks like this:

struct Symbol
{
    Symbol()=default;
    explicit Symbol(const char*);
};

Now I want to write an example for documentation purposes that initializes an array (array/vector/list - I don't care about the exact type) and I need the example to be as clear and concise as possible. Ideally it would look like this:

Symbol symbols[] = { "a", "b", "c"};

That does not compile because of the explicit keyword and I am not prepared to make the constructor implicit.

How can I make this work, with the focus of making the example code as expressive as possible?

EDIT: I went for Bolov's solution with a little help from Caleth:

struct Symbol
{
    Symbol();
    explicit Symbol(const char*);

    template <class... Args> 
    static std::array<Symbol, sizeof...(Args)> Array(Args... args)
    {
        return {Symbol{args}...}; 
    } 
};

int main()
{
    auto symbols = Symbol::Array("a", "b", "c");
}

回答1:


Well, your constructor is explicit so you need to use it as such:

Symbol symbols[] = {Symbol{"a"}, Symbol{"b"}, Symbol{"c"}};

Both gcc and clang both the copy/move constructor and since C++17 that is the required behavior so there is no performance overhead.


If you really want to keep the constructor explicit and be able to create an array without explicitly stating it for every element then you can create a helper function:

template <class... Args,
          class Enable = std::enable_if_t<(... && std::is_same_v<Args, const char*>)>>
auto make_symbols(Args... args) -> std::array<Symbol, sizeof...(Args)>
{
    return {Symbol{args}...};
}

and use it like this:

auto symbols = make_symbols("a", "b", "c");

Again the move/copies are entirely elided.

The make_symbols function uses C++17 features for checking the arguments types. If you need the constraint for a previous standard version (including C++11) see this answer Restrict variadic template arguments. Or, depending on your needs, removing the check can also be a choice.




回答2:


The best I've come up with so far is:

std::vector<Symbol> symbols;
for(auto v: { "a", "b", "c"})
    symbols.emplace_back(v);


来源:https://stackoverflow.com/questions/48742738/initializing-array-through-explicit-constructor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!