How to initializing a const set with list of values?

I want to initialize in the preambulum, so I dont want to define and initialize an array before initializing the set. I want to do this in one row, if it is possible.

Dani AI

Generated

In modern C++ (C++11 and later), you can initialize a const std::set directly with a braced list. No helper macros, arrays, or temporary containers needed.

#include <set>

const std::set<int> ids{100, 400, 200, 300, 500};  // one line

A few tips to make this robust:

  • Duplicates are ignored automatically: {1,2,2,3} becomes {1,2,3}.
  • If you want a custom order, pass a comparator:
const std::set<int, std::greater<int>> desc{1, 3, 2};  // elements kept in 3,2,1
  • C++17 lets you skip the type on the left via class template argument deduction:
const std::set s{1, 2, 3};  // deduces std::set<int>

If you need a single definition that is safely initialized exactly once and you care about startup order, wrap it in a function-local static:

const std::set<int>& allowedIds() {
    static const std::set<int> s{10, 20, 30};
    return s;  // thread-safe since C++11
}

The approaches shown by and were clever workarounds before brace-init was widely available. Today, prefer the brace-initializer for clarity and zero extra machinery. One last gotcha: if you are storing text, avoid set<const char*> (it orders by pointer value). Use set<std::string> instead:

const std::set<std::string> names{"alice", "bob", "carol"};

That should give you a clean, one-line, in-place initialization that stays const.

Recommended Answers

All 3 Replies

Maybe not the best way to do it, but it most certainly is an option:

#include <iostream>
#include <set>

template <class T>
struct SetMaker
{
    std::set<T> data;

    SetMaker & operator << (const T & element)
    { data.insert(element); return *this; }

    SetMaker & operator , (const T & element)
    { data.insert(element); return *this; }
};

#define MAKE_SET_1(T, x1) (SetMaker<T>() << x1).data
#define MAKE_SET_2(T, x1, x2) (SetMaker<T>() << x1, x2).data
#define MAKE_SET_3(T, x1, x2, x3) (SetMaker<T>() << x1, x2, x3).data
#define MAKE_SET_4(T, x1, x2, x3, x4) (SetMaker<T>() << x1, x2, x3, x4).data
#define MAKE_SET_5(T, x1, x2, x3, x4, x5) (SetMaker<T>() << x1, x2, x3, x4, x5).data

// etc...

int main()
{
    const std::set<int> my_set(MAKE_SET_5(int, 100, 400, 200, 300, 500));

    std::set<int>::const_iterator cur_it = my_set.begin();
    std::set<int>::const_iterator end_it = my_set.end();

    while (cur_it != end_it) { std::cout << *cur_it << " "; ++cur_it; }

    std::cout << "\n(hit enter to quit...)"; std::cin.get();

    return 0;
}

Boost.Assignment could help too -> http://www.boost.org/doc/libs/1_46_1/libs/assign/doc/index.html

Forget the above. Let's do it the boost way:

#include <iostream>
#include <vector>
#include <list>
#include <set>

template <class T>
struct ListMaker
{
    std::list<T> data;

    ListMaker & operator ()(const T & element) { data.push_back(element); return *this; }

    template <class Container>
    operator Container() { return Container(data.begin(), data.end()); }
};

template <class T>
ListMaker<T> list_of(const T & element) { return ListMaker<T>()(element); }

template <class Container>
void print_container(const Container & c)
{
    typename Container::const_iterator cur_it = c.begin();
    typename Container::const_iterator end_it = c.end();

    while (cur_it != end_it) { std::cout << *cur_it << " "; ++cur_it; }

    std::cout << std::endl;
}

int main()
{
    const std::vector<int> my_vector = list_of(10)(9)(8)(7)(6)(5)(4)(3)(2)(1);
    const std::set<int>    my_set    = list_of(10)(9)(8)(7)(6)(5)(4)(3)(2)(1);

    print_container(my_vector);
    print_container(my_set);

    std::cout << "\n(hit enter to quit...)"; std::cin.get();

    return 0;
}

There's a lot of copying involved, but the interface is way cleaner.
Peeking at Boost.Assignment source code could still be useful though.

Using a trick I borrowed from http://www.daniweb.com/software-development/cpp/threads/41594, I did the following:

#include <iostream>
#include <set>

using namespace std;

template <typename T, int N>
char (&array(T(&)[N]))[N];

int init[] = {1, 2, 3, 4, 5, 6, 7, 8, 9 };

set<int> myInts ( init, init + sizeof array ( init ) );

int main()
{
  set<int>::iterator it = myInts.begin();

  while ( it != myInts.end() ) {
    cout << *it << endl;
    ++it;
  }
}

Not sure if this is what you want.
-lou

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.