Alternatywa dla brace initializer list w c++03

0

Cześć,
Borykam się z natępującym problemem.

std::map<std::string, std::vector<uint16_t>>

Zawartość mapy ma być wartością stałą, niemodyfikowaną podczas działania programu.
W normalnych warunkach nie stanowi to problemu, wystarczy użyć brace initialization list.
Problemem jest jednak statyczna analiza kodu, która nie wspiera powyższego rozwiązania, pomimo teoretycznej obsługi c++11 w projekcie(problem nie do przeskoczenia).
Mogę dodawać poszczególne wartości do mapy w ramach pojedyńczej metody, w następujący sposób:

mapa.insert(std::pair<std::string, std::vector<uint16_t>>("arg1", {1, 2, 3}));

Niestety powyższy przypadek wciąż nie unika wykorzystania nawiasów klamrowych.

Czy macie może pomysł jak rozwiązać powyższy problem, bez wykorzystywania długich i bardzo brzydkich konstrukcji?

4

Jeżeli jesteś ograniczony do standardu C++03, to jedynym wyjściem jakie widzę to jest użyć biblioteki boost https://www.boost.org/doc/libs/1_36_0/libs/assign/doc/index.html

#include <map>
#include "boost/assign.hpp"
using namespace std;
using namespace boost::assign;

map<string, vector<uint16_t>> mymap = map_list_of ("key1", list_of(1)(2)(3) ) ("key2", list_of(7)(3)(3) ) ("key3", list_of(5)(2)(7) ) ;

Kod wpisałem z pamięci, więc mogą być jakieś błędy związane ze składnią.

4

Jak nie chcesz boosta i nie masz c++11 to możesz ew. sam wszystko zaimplementować:

1

Najłatwiej, jeśli to możliwe, po prostu wyłączyć lintera dla tego fragmentu kodu. Np. clang-tidy nie sprawdza linii oznaczonych komentarzem NOLINT:

const std::map<std::string, std::vector<uint16_t>> const_map { // NOLINT
    { "key 0", { 0, 1, 2 } }, // NOLINT
    { "key 1", { 3, 4, 5 } } // NOLINT
}; // NOLINT

IMHO w tym wypadku byłoby to uzasadnione.

Sensowna alternatywa to wzorzec budowniczego:

template<typename KeyType, typename ValueType>
struct MapBuilder
{
    std::map<KeyType, ValueType> result;

    MapBuilder& add(KeyType key, ValueType value)
    {
        result.emplace(std::move(key), std::move(value));
        return *this;
    }
};

template<typename ValueType>
struct VectorBuilder
{
    std::vector<ValueType> result;

    VectorBuilder& add(ValueType value)
    {
        result.push_back(std::move(value));
        return *this;
    }
};

const auto const_map = MapBuilder<std::string, std::vector<uint16_t>>()
    .add("key 0", VectorBuilder<uint16_t>().add(0).add(1).add(2).result)
    .add("key 1", VectorBuilder<uint16_t>().add(3).add(4).add(5).result)
    .result;
0
Nunn napisał(a):

Problemem jest jednak statyczna analiza kodu, która nie wspiera powyższego rozwiązania, pomimo teoretycznej obsługi c++11 w projekcie(problem nie do przeskoczenia).

To w końcu jak to jest? Masz to C++11 i tylko statyczna analiza kodu nie radzi sobie z tym przypadkiem? Czy może nie możesz używać C++11?

Jeśli jest to problem ze statyczna analiza kodu to raczej powinieneś opisać jakie to narzędzie i rozważył użycie jakiejś alternatywy.
Nie może być tak, że dostosowujesz kod do braków narzędzia analizy kodu.

0

Możesz też pokombinować z ranged konstruktorem i tablicami - zamiast iteratorów dajesz wskaźnik na tab[0] i tab[n] (https://en.cppreference.com/w/cpp/container/map/map - wariant nr 2 + to samo dla vectora), ale to nie będzie najwydajniejsze.
Poza tym możesz spróbować użyć std::initializer_list bezpośrednio - jak Ci ten tool to łyknie, to będzie wydajniej niż pomysł powyżej.

1 użytkowników online, w tym zalogowanych: 0, gości: 1