Kly*_*pto 5 c++ operator-overloading c++11
我有一个类,它既具有到内在类型的隐式转换操作符(),又能够通过用于设置存储的字符串索引操作符[]进行访问。它在 gcc 6.3 和 MSVC 的单元测试中编译和运行得很好,但是该类会在智能感知和 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]);
}
}
};
Run Code Online (Sandbox Code Playgroud)
用法:
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
Run Code Online (Sandbox Code Playgroud)
错误信息如下:
多个运算符“[]”与这些操作数匹配:
内置运算符“整数[对象指针]”函数
“设置::运算符[](std::字符串键)”
操作数类型有: 设置 [ const char [15] ]
我理解为什么存在错误/警告,因为它来自于使用数组本身反转数组上的索引器的能力(这本身就是极其奇怪的语法,但对于指针算术来说具有逻辑意义)。
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
Run Code Online (Sandbox Code Playgroud)
我不确定如何避免它呈现的错误消息,同时保持我想要完成的任务。(隐式赋值和字符串索引)
那可能吗?
注意:我无法使用 11 以上的 C++ 功能。
问题是用户定义的隐式转换函数模板。
template<typename T>
operator T()
{
return data;
}
Run Code Online (Sandbox Code Playgroud)
当编译器考虑表达式时data["TestNode"]
,需要进行一些隐式转换。编译器有两个选项:
const char [9]
为 aconst std::string
并调用Setting &Setting::operator[](const std::string)
Setting
为 anint
并调用const char *operator[](int, const char *)
这两个选项都涉及隐式转换,因此编译器无法决定哪一个更好。编译器说该调用不明确。
有几种方法可以解决这个问题。
const char [9]
消除从到 的隐式转换std::string
。Setting::operator[]
您可以通过创建一个接受字符数组引用(对字符串文字的引用)的模板来完成此操作。
template <size_t Size>
Setting &operator[](const char (&key)[Size]);
Run Code Online (Sandbox Code Playgroud)
Setting
消除从到 的隐式转换int
。您可以通过将用户定义的转换标记为 来完成此操作explicit
。
template <typename T>
explicit operator T() const;
Run Code Online (Sandbox Code Playgroud)
这将要求您更新调用代码以使用直接初始化而不是复制初始化。
int x{data["TestNode"]};
Run Code Online (Sandbox Code Playgroud)
Setting
消除从到 的隐式转换int
。另一种方法是完全删除用户定义的转换并使用函数。
template <typename T>
T get() const;
Run Code Online (Sandbox Code Playgroud)
显然,这还需要您更新调用代码。
int x = data["TestNode"].get<int>();
Run Code Online (Sandbox Code Playgroud)
我注意到关于代码的一些事情是您没有将用户定义的转换标记为const
. 如果成员函数不修改对象,则应将其标记为const
能够在常量对象上使用该函数。所以放在const
参数列表后面:
template<typename T>
operator T() const {
return data;
}
Run Code Online (Sandbox Code Playgroud)
我注意到的另一件事是:
std::shared_ptr<Setting>(new Setting())
Run Code Online (Sandbox Code Playgroud)
在这里,您提到Setting
两次并在可以执行一次内存分配时执行两次内存分配。为了代码的整洁和性能,最好这样做:
std::make_shared<Setting>()
Run Code Online (Sandbox Code Playgroud)
另一件事,我对你的设计了解不够,无法自己做出这个决定,但你真的需要使用吗std::shared_ptr
?我不记得上次使用std::shared_ptr
asstd::unique_ptr
是什么时候了,它效率更高,并且在大多数情况下似乎就足够了。真的,你真的需要一个指针吗?使用std::shared_ptr<Setting>
或std::unique_ptr<Setting>
超过有什么理由吗Setting
?只是需要思考一下。