什么是创建包含1个元素的集合的最佳/最简单/最快方法?(C++)

6
有时候我需要使用用户类型的一元素集合(或任何其他容器)并通过以下方式创建它们:
boost::assign::list_of(typeVariable).convert_to_container<std::unordered_set<UserType> >()

有没有更加优美的方式呢?

PS: 例如,我们有一个业务逻辑API,它搜索元素,并且需要选择一组类型用于筛选。不同的用户可以访问不同的类型。此外,我们可以选择任何一种类型进行过滤,这种情况下,我们将从过滤选项中选择这一种类型。

因此,我只想要用一行简单的代码来实现。我的当前版本是:

getElements(filter.type != UNDEFINED
            ? boost::assign::list_of(filter.type).convert_to_container<std::set<UserType> >()
            : std::set<UserType>(allowedTypes.begin(), allowedTypes.end()))

5
为什么需要一个只有一个元素的集合?你后续会扩充这个集合,还是它始终只有一个元素? - rbaleksandar
这似乎是一个关于如何创建设计缺陷的问题。您似乎试图将大量逻辑放入单行代码中,这使得该行不易读取,因此难以维护。 - Zac Howland
4个回答

5
std::unordered_set<UsertType> set = {typeVariable}

或者针对包含作为临时生成的一组完整工作代码:
#include <iostream>
#include <unordered_set>
using namespace std;

int main() {
    /* First (unused in the rest of the code) set */
    std::unordered_set<int> set = {1};

    /* Set generated on the fly, if you don't even want to create
       a variable for it */
    cout << *std::unordered_set<int>({2}).begin() << endl;

    return 0;
}

@pavelalexeenko 为什么?getElements(filter.type != UNDEFINED ? std::set<UserType>({filter.type}): std::set<UserType>(allowedTypes.begin(), allowedTypes.end()))。这里没有任何不标准的地方。 - coyotte508

5

很遗憾,在C++中,您不能简单地使用auto set={2.3};,因为这创建的不是一个集合,而是一个std::initializer_list。但是,通过以下方式可以帮助解决:

template<typename Tp>
inline std::unordered_set<Tp> make_set(Tp const&x)
{ return {x}; }

您可以使用:

auto set = make_set(2.3);

不需要显式指定set类型(如其他答案中所示)。

您可以扩展make_set()以接受相同类型的任意数量参数(我将其留给您作为练习),但更容易添加一个接受初始化列表的重载。

template<typename Tp>
std::unordered_set<Tp> make_set(std::initializer_list<Tp> const&x)
{ return {x}; }

何时

auto set = make_set({2.3,3.1});

使用两个元素创建一个std::unordered_set<double>

编辑 在我看来,似乎没有纯粹的std解决方案可以避免显式命名集合的类型(std::unordered_set<possibly_templated_user_type>)。因此,make_set()(或类似函数)是唯一的解决方案,可以由std提供(类似于std::make_unique()std::make_shared())。


这可能是最简单的方法,但我仍在寻找标准库\boost决策。 - pavelalexeenko
@bolov,这是一个有趣的C++17扩展,避免了命名模板参数,在许多情况下使生活更加轻松。因此,如果支持编译器,您将能够说std::unordered_set{x} - Walter
我的C++11解决方案避免了对集合或元素类型进行命名 /cc @bolov - sehe
@sehe,你实际上操纵了用户端(getElement()在后来的编辑中才被添加到PO中),从本质上要求进行大量重载。但我认为PO想要调用各种类似的函数。 - Walter

2

利用指向对象的指针可以用作单元素迭代器的事实:

auto x = f();
std::set<T> xs(&x, &x + 1);

2
从技术上讲,这将对象视为包含该对象的单元素数组。指针是实际的迭代器,而不是指向的对象。 - MSalters
@bolov 不,这不是未定义行为。有一条特殊规则允许这样做。https://dev59.com/RmUq5IYBdhLWcg3wbv5Z#14505930 - user1804599
@rightfold 不错的发现。如果我之前能读到那段话,那该多好啊……我的过失。 - bolov

1

UPDATE Note that if the getElements function already takes an explicitly typed set<...> const& you can simply write:

if (...)
    getElements({ filter.type});
else
    getElements({ allowedTypes.begin(), allowedTypes.end() });

That uses C++ uniform initialization and initializer list syntax

假设您有以下API:
template <typename Container>
void getElements(Container const& xs);

// usage:    
getElements(std::vector<int> {1, 2});
getElements(std::list<std::string> {"1", "2"});

我认为您正在寻找一个额外的界面,如下所示:
template <typename V>
void getElements(std::initializer_list<V> const& xs) { 
    getElements(std::set<V>(xs));
}

演示

在Coliru上实时运行

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

template <typename Container>
void getElements(Container const& xs) { 
    std::cout << __PRETTY_FUNCTION__ << " ";
    for(auto& x : xs) std::cout << x << ";";
    std::cout << "\n";
}

template <typename V>
void getElements(std::initializer_list<V> const& xs) { 
    getElements(std::set<V>(xs));
}

int main() {
    getElements(std::vector<int> {1, 2});
    getElements(std::list<std::string> {"1", "2"});

    getElements({1});
    getElements({1, 2});
}

打印
void getElements(const Container&) [with Container = std::vector<int>] 1;2;
void getElements(const Container&) [with Container = std::__cxx11::list<std::__cxx11::basic_string<char> >] 1;2;
void getElements(const Container&) [with Container = std::set<int, std::less<int>, std::allocator<int> >] 1;
void getElements(const Container&) [with Container = std::set<int, std::less<int>, std::allocator<int> >] 1;2;

这仍然无法执行所需的 getElement(filter.type != UNDEFINED? single_element : many_elements) 调用。 - Walter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接