我有一个类,它既具有对内在类型的隐式转换operator(),又具有通过用于设置存储的字符串索引operator []进行访问的能力。它在gcc 6.3和MSVC的单元测试中可以编译并很好地工作,但是该类在intellisense和clang上引起了一些歧义性警告,这是不可接受的。
超级瘦身版:https : //onlinegdb.com/rJ-q7svG8
#include <memory>
#include <unordered_map>
#include <string>
struct Setting
{
int data; // this in reality is a Variant of intrinsic types + std::string
std::unordered_map<std::string, std::shared_ptr<Setting>> children;
template<typename T>
operator T()
{
return data;
}
template<typename T>
Setting & operator=(T val)
{
data = val;
return *this;
}
Setting & operator[](const std::string key)
{
if(children.count(key))
return *(children[key]);
else
{
children[key] = std::shared_ptr<Setting>(new Setting());
return *(children[key]);
}
}
};
用法:
Setting data;
data["TestNode"] = 4;
data["TestNode"]["SubValue"] = 55;
int x = data["TestNode"];
int y = data["TestNode"]["SubValue"];
std::cout << x <<std::endl;
std::cout << y;
output:
4
55
错误信息如下:
多个运算符“ []”与以下操作数匹配:
内置运算符“整数[指针到对象]”功能
“ Setting :: operator [](std :: string键)”
操作数类型为:设置[const char [15]]
我理解为什么错误/警告之所以存在,是因为它具有使用数组本身来反转数组中索引器的能力(其本身是极其奇怪的语法,但在指针算术中具有逻辑意义)。
char* a = "asdf";
char b = a[5];
char c = 5[a];
b == c
我不确定如何避免显示错误消息,同时又保持我想要完成的工作。(隐式赋值和按字符串索引)
那可能吗?
注意:我不能使用11以上的C ++功能。
问题是用户定义的隐式转换功能模板。
template<typename T>
operator T()
{
return data;
}
当编译器考虑表达式时data["TestNode"]
,需要进行一些隐式转换。编译器有两个选项:
const char [9]
为const std::string
并调用Setting &Setting::operator[](const std::string)
Setting
为int
并调用const char *operator[](int, const char *)
这两个选项都涉及隐式转换,因此编译器无法确定哪个更好。编译器说该调用是模棱两可的。
有几种方法可以解决此问题。
消除从const char [9]
到的隐式转换std::string
。您可以通过创建Setting::operator[]
一个模板来实现此目的,该模板接受对字符数组的引用(对字符串文字的引用)。
template <size_t Size>
Setting &operator[](const char (&key)[Size]);
消除从Setting
到的隐式转换int
。您可以通过将用户定义的转换标记为来实现explicit
。
template <typename T>
explicit operator T() const;
这将要求您更新调用代码以使用直接初始化而不是复制初始化。
int x{data["TestNode"]};
消除从Setting
到的隐式转换int
。另一种方法是通过完全删除用户定义的转换并使用一个函数。
template <typename T>
T get() const;
显然,这还需要您更新调用代码。
int x = data["TestNode"].get<int>();
我注意到有关代码的一些事情是您没有将用户定义的转换标记为const
。如果成员函数未修改该对象,则应将其标记为const
能够在恒定对象上使用该函数。因此放在const
参数列表之后:
template<typename T>
operator T() const {
return data;
}
我注意到的另一件事是:
std::shared_ptr<Setting>(new Setting())
在这里,您提到Setting
两次,并且一次可能要进行两次内存分配。对于代码清洁度和性能,最好这样做:
std::make_shared<Setting>()
还有一件事,我对您的设计不了解,无法自己做出决定,但是您真的需要使用std::shared_ptr
吗?我不记得我最后一次使用std::shared_ptr
的std::unique_ptr
是更有效,似乎是足够在大多数情况下。确实,您是否完全需要一个指针?是否有使用std::shared_ptr<Setting>
或std::unique_ptr<Setting>
结束的理由Setting
?只是要考虑的事情。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句