2016-07-05 8 views

답변

5

문제는 std::initializer-list의 내용을 복사하는 것입니다. (의 객체는 const) 본질적으로 의 객체입니다. ... 당신은 별도의 함수에서지도를 초기화 할 수 있습니다

std::map<int, std::unique_ptr<MyClass>> init(){ 
    std::map<int, std::unique_ptr<MyClass>> mp; 
    mp[0] = std::make_unique<MyClass>(); 
    mp[1] = std::make_unique<MyClass>(); 
    //...etc 
    return mp; 
} 

을 그리고 그것을 Live On Coliru

+0

'init()'이'std :: map <...> &&'(rvalue)를 반환한다면 차이가 있을까요? 나는. 가치를 반환하는 것이 더 좋을까요? Upd : rvalue를 사용하면 segfault – vladon

+1

@vladon이 발생합니다. 그렇게하는 것은 성능상의 단순화가 아니라 버그이기도합니다. 'rvalue' 참조를 파괴 된 객체로 반환 할 것입니다. [this] (http://stackoverflow.com/questions/4986673/c11-rvalues-and-move-semantics-confusion-return-statement) ...를 참조하십시오.값으로 반환하는 것은 이와 같은 경우 매우 효율적입니다. 왜냐하면 [확실하게 (C++ 17)] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0. html) [RVO] 즐기기 (http://en.cppreference.com/w/cpp/language/copy_elision) – WhiZTiM

1

다른 방법이하는 것입니다을 참조하십시오

static void f() 
{ 
    static std::map<int, std::unique_ptr<MyClass>> mp = init(); 
} 

호출 : 가 문제를 해결하려면 람다를 사용하십시오. 그것은 별도의 함수를 사용하는 것과 같지만 맵의 초기화를 액션에 가깝게 만듭니다. 이 경우 필자는 &과 decltype의 조합을 사용하여 맵의 이름을 지정하지 않아도되었지만 재미를 위해서입니다.

람다에 전달 된 인수는 호출 시점에서 아직 생성되지 않은 객체에 대한 참조이므로 어떤 식 으로든 참조하지 말아야합니다. 유형 차감에만 사용됩니다.

#include <memory> 
#include <map> 
#include <utility> 

struct MyClass {}; 


static auto& f() 
{ 
    static std::map<int, std::unique_ptr<MyClass>> mp = [](auto& model) 
    { 
    auto mp = std::decay_t<decltype(model)> {}; 
    mp.emplace(0, std::make_unique<MyClass>()); 
    mp.emplace(1, std::make_unique<MyClass>()); 
    return mp; 
    }(mp); 
    return mp; 
} 

int main() 
{ 
    auto& m = f(); 
} 

다른 방법이 있습니다. 이 경우에 우리는 람다에 일시적으로 전달하고 copy elision/RVO에 의존합니다.

#include <memory> 
#include <map> 
#include <utility> 

struct MyClass {}; 

static auto& f() 
{ 
    static auto mp = [](auto mp) 
    { 
    mp.emplace(0, std::make_unique<MyClass>()); 
    mp.emplace(1, std::make_unique<MyClass>()); 
    return mp; 
    }(std::map<int, std::unique_ptr<MyClass>>{}); 
    return mp; 
} 

int main() 
{ 
    auto& m = f(); 
} 

또 다른 방법으로, 가변 λ에서 람다 캡쳐를 이용하는 것.

#include <memory> 
#include <map> 
#include <utility> 

struct MyClass {}; 

static auto& f() 
{ 
    static auto mp = [mp = std::map<int, std::unique_ptr<MyClass>>{}]() mutable 
    { 
    mp.emplace(0, std::make_unique<MyClass>()); 
    mp.emplace(1, std::make_unique<MyClass>()); 
    return std::move(mp); 
    }(); 
    return mp; 
} 

int main() 
{ 
    auto& m = f(); 
} 
1

맞춤형 크레스트 코드를 쓰는 것은 지루하고 명백하게됩니다.

여기서는 비교적 효율적인 일반 컨테이너 초기화 코드입니다. 이니셜 라이저 목록처럼 임시로 std::array에 데이터를 저장하지만, const이 아닌 mives가됩니다.

make_map은 짝수 개의 요소를 사용하며, 첫 번째 요소는 두 번째 값을 나타냅니다. 오타를 금지 ...

static std::map<int, std::unique_ptr<MyClass>> = 
    make_map(0, std::make_unique<MyClass>()); 

:

template<class E, std::size_t N> 
struct make_container_t{ 
    std::array<E,N> elements; 
    template<class Container> 
    operator Container()&&{ 
    return { 
     std::make_move_iterator(begin(elements)), 
     std::make_move_iterator(end(elements)) 
    }; 
    } 
}; 
template<class E0, class...Es> 
make_container_t<E0, 1+sizeof...(Es)> 
make_container(E0 e0, Es... es){ 
    return {{{std::move(e0), std::move(es)...}}}; 
} 

namespace details{ 
    template<std::size_t...Is, class K0, class V0, class...Ts> 
    make_container_t<std::pair<K0,V0>,sizeof...(Is)> 
    make_map(std::index_sequence<Is...>, std::tuple<K0&,V0&,Ts&...> ts){ 
    return {{{ 
     std::make_pair(
     std::move(std::get<Is*2>(ts)), 
     std::move(std::get<Is*2+1>(ts))) 
    )... 
    }}}; 
    } 
} 
template<class...Es> 
auto make_map(Es... es){ 
    ststic_assert(!(sizeof...(es)&1), "key missing a value? Try even arguments."); 
    return details::make_map(
    std::make_index_sequence<sizeof...(Es)/2>{}, 
    std::tie(es...) 
); 
} 

이 그것으로 줄여야합니다.

관련 문제