我有一个类,它具有将运算符()隐式转换为内部类型的功能,并且能够通过用于设置存储的字符串索引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错误消息如下:
多个运算符"[]“匹配这些操作数:
内建运算符“整指针到对象”函数
“设置::操作员std::string key”
操作数类型为:设置[ const char 15 ]
我理解错误/警告存在的原因,因为它能够用数组本身反转数组上的索引器(这本身是非常奇怪的语法,但指针算法具有逻辑意义)。
char* a = "asdf";
char b = a[5];
char c = 5[a];
b == c我不知道如何避免它所呈现的错误信息,同时保持我想要完成的目标。(隐式赋值&字符串索引)
这有可能吗?
注意:我不能在11以上使用C++特性。
发布于 2020-02-05 02:54:26
问题是用户定义的隐式转换函数模板。
template<typename T>
operator T()
{
return data;
}当编译器考虑表达式data["TestNode"]时,需要进行一些隐式转换。编译器有两个选项:
Setting &Setting::operator[](const std::string)
const char [9]转换为const std::string,并将Setting调用为int并调用const std::string这两个选项都涉及隐式转换,因此编译器无法决定哪个更好。编译器说调用是不明确的。
有几种方法可以绕过这件事。
备选案文1
消除从const char [9]到std::string的隐式转换。您可以通过使Setting::operator[]成为接受对字符数组(对字符串文字的引用)的引用的模板来做到这一点。
template <size_t Size>
Setting &operator[](const char (&key)[Size]);选项2
消除从Setting到int的隐式转换。您可以通过将用户定义的转换标记为explicit来做到这一点。
template <typename T>
explicit operator T() const;这将要求您更新调用代码,以使用直接初始化而不是复制初始化。
int x{data["TestNode"]};选项3
消除从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?只是想点什么。
https://stackoverflow.com/questions/60068103
复制相似问题