使用大括号初始化方式初始化std::shared_ptr<std::map<>>

8

我有一个指向mapshared_ptr

std::shared_ptr<std::map<double, std::string>>

我希望使用花括号初始化它。这样做是否可行?

我尝试过:

std::string s1("temp");
std::shared_ptr<std::map<double, std::string>> foo = std::make_shared<std::map<double, std::string>>(1000.0, s1);

但是在使用Xcode 6.3编译时,会出现以下错误:

/usr/include/c++/v1/map:853:14: Candidate constructor not viable: no known conversion from 'double' to 'const key_compare' (aka 'const std::__1::less<double>') for 1st argument

我已经尝试过其他不同的第一个参数(1000.0),但都没有成功。

有人可以帮忙吗?


可能的,但不太优美的代码:std::shared_ptr<std::map<double, std::string>> foo = std::make_shared<std::map<double, std::string>>(std::initializer_list<std::map<double, std::string>::value_type>{{1000.0, s1}}); - Piotr Skotnicki
std::shared_ptr<std::map<double, std::string>> foo = std::make_shared<std::map<double, std::string>>(std::map<double, std::string>{{1000.0, s1}}); 但仍不够好。 - Piotr Skotnicki
可以,我注意到了value_type的使用。我发现它只是typedef pair<const Key, Type>。那我为什么需要它呢? - ksl
问题在于你添加的一个对象是std::pair<T1,T2>,因此你需要在花括号初始化列表中放置std::pair。编辑:显然是map。 - Incomputable
6个回答

10

std::map有一个初始化列表构造函数:

map (initializer_list<value_type> il,
     const key_compare& comp = key_compare(),
     const allocator_type& alloc = allocator_type());

我们可以轻松地使用此构造函数创建一个地图:
std::map<double,std::string> m1{{1000.0, s1}};

要在make_shared中使用它,我们需要指定提供的initializer_list的哪个实例:

auto foo = std::make_shared<std::map<double,std::string>>
           (std::initializer_list<std::map<double,std::string>::value_type>{{1000.0, s1}});

这看起来很笨拙;但如果您需要经常使用它,您可以使用别名使其更整洁:

#include <string>
#include <map>
#include <memory>

std::string s1{"temp"};

using map_ds = std::map<double,std::string>;
using il_ds = std::initializer_list<map_ds::value_type>;

auto foo = std::make_shared<map_ds>(il_ds{{1000.0, s1}});

您可以选择定义一个模板函数来包装该调用:
#include <string>
#include <map>
#include <memory>

template<class Key, class T>
std::shared_ptr<std::map<Key,T>>
make_shared_map(std::initializer_list<typename std::map<Key,T>::value_type> il)
{
    return std::make_shared<std::map<Key,T>>(il);
}

std::string s1{"temp"};
auto foo = make_shared_map<double,std::string>({{1000, s1}});

2
你可以将 il_double_to_string 设为别名模板,这样它就可以与任何映射类型一起使用。类似于 这样 - TartanLlama
如果有关系的话,我使用GCC 4.8.2来测试上述内容。 - Toby Speight

1

你的问题在于你没有在初始化器中放置任何大括号。我需要以下内容才能使其正常工作:

auto foo = std::make_shared<std::map<double, std::string> >(
                         std::map<double, std::string>({{1000.0, s1}})
           );

双重的 std::map<double, std::string> 让我感到困扰。它应该能够在给定另一个条件的情况下解决其中一个问题... 但是 gcc 5.3.0 不支持。

你肯定需要双括号。(一次表示你正在初始化一个映射,一次用于分隔每个条目。)


1
创建一个initializer_list,从中构造一个map,然后复制该map。更好的方法是直接将initializer_list传递给make_shared,避免map的复制。 - Jonathan Wakely
绝对同意。(虽然复制地图的机会可能是一次移动,因此它并不是非常昂贵) 我无法让它工作。 - Martin Bonner supports Monica
...而Toby Speight已经给出了正确的答案。 - Martin Bonner supports Monica

1

你可以不使用 std::make_shared 来完成它:

std::shared_ptr<std::map<double,std::string>> ptr(new std::map<double,std::string>({{1000.0, "string"}}));

0
这是对Toby Speight答案的完善和概括。
template<class Container>
std::shared_ptr<Container>
make_shared_init_list(std::initializer_list<typename Container::value_type> il) {
    return std::make_shared<Container>(il);
}

使用方法:

auto foo = make_shared_init_list<std::map<double,std::string>>({{1000, "hi"}});

优点是它通过接受map作为模板参数而保留了unique_ptr的使用方式。它还可以透明地与map、unordered_map或任何其他能够接受初始化列表的容器构造函数一起使用。

-2

类似这样的东西应该可以做到...

 std::string s1("temp");  

 std::map<double, std::string> *m = new std::map<double, std::string>{{100., s1}};

 auto foo = std::shared_ptr<std::map<double, std::string>>(m);

或者作为一行代码

auto foo2 = std::shared_ptr<std::map<double, std::string>>(new std::map<double, std::string>{{100., s1}});

(抱歉,一开始忘记了初始化列表的要求)


-4

更改键的类型。

double 是键的不良类型,因为它没有 operator==,而且不同的字节序列可以表示相同的浮点值。


1
std::map并不关心operator==,因为它不使用它。 - Jonathan Wakely
1
不一定。如果您将已知值插入到映射中,则键将恰好具有这些值。浮点数并非不确定且受量子波动影响。使用浮点数作为映射键的问题在于 NaN 与其他值无序。 - Jonathan Wakely
1
@JonathanWakely:“确切的那些值”——除了0.1可能不等于1./10.,特别是如果第一个是字面量,而第二个是涉及给定值的两个变量的表达式。但是,是的,可以小心地完成。 - Martin Bonner supports Monica
2
@jonezq,不,它**不依赖于实现。std::map不允许使用operator== - Jonathan Wakely
1
@jonezq:他的意思不是这样。如果你创建一个键为0.0的映射,那么你可以搜索负零并找到0.0元素。如果你搜索NaN元素(它与其他值无序),则会发生糟糕的事情。如果你创建一个键为0.1(字面量)的元素,然后搜索字面量0.1,你会找到它。如果你搜索(1.0/10.0),你可能找不到元素。如果你找到了一个元素,那么你搜索的值将与键相等。 - Martin Bonner supports Monica
显示剩余7条评论

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