我的这个类有一个map属性,其值是boost :: variant。
typedef boost::variant<char, int, bool, unsigned short, float, timeval, double > MultiType;
class A {
public:
template<class T>
T& operator[](const std::string& key) {
return boost::get<T>(map_[key]);
}
template<class T>
std::string keyTypeToString(const std::string& key) {
std::stringstream ss;
ss << boost::get<T>(map_[key]);
return ss.str();
}
private:
std::map<std::string, MultiType> map_;
};
来自main:
A a;
a["param"];
编译器报告此错误:
../ src / main.cpp:8:25:错误:'a [“param”]'中'运算符[]'不匹配 ../src/main.cpp:8:25:注意:候选人是:
../src/util/A.h:53:5:注意:模板T&amp; A :: operator [](const string&amp;)
也许我错过了一些微不足道的事情,但我无法理解我错在哪里......
答案 0 :(得分:4)
从这开始:
template<class T>
T& get(const std::string& key) {
return boost::get<T>(map_[key]);
}
您可以将其称为a.get<int>("hello")
,其中元素"hello"
为int
。
接下来,写下这个:
struct pseudo_ref {
std::string const& str;
A* a;
template<typename T>
operator T&()&&{
return a->get<T>(str);
}
template<typename T>
pseudo_ref operator=( T&& t ) && {
a->get<typename std::decay<T>::type>(str) = std::forward<T>(t);
return {str, a};
}
pseudo_ref(pseudo_ref const&)=delete;
pseudo_ref& operator=(pseudo_ref const&)=delete;
pseudo_ref( std::string const& s, A* a_ ):str(s), a(a_) {}
};
然后回到A
:
pseudo_ref operator[](std::string const& str) {
return {str, this};
}
我们得到[]
神奇地为你转换,只要你使用完全正确的类型分配/读取它。
这有点危险,但很酷。
如果您想要const
pseudo_ref,则需要另一个类来表示它(没有=
和operator T const&
而不是operator T&
。)
在实践中,这种malarkey很少值得。
我在C ++ 11中写过这个,因为在C ++ 03中编写它会稍微有点痛苦(并且遇到pseudo_ref
的终生问题 - 如果你有auto&& x = a["hello"]
它们仍然存在),疼痛少就好了。
答案 1 :(得分:3)
template<class T>
T& operator[](const std::string& key) {
return boost::get<T>(map_[key]);
}
编译器无法从T
之类的调用中推断出a["param"];
。您需要明确指定
a.operator[]<int>("param");
我怀疑你是在追求什么,但我知道什么。
答案 2 :(得分:3)
class A {
public:
class proxy {
friend class A;
private:
MultiType& it;
proxy(MultiType& it): it(it) {}
public:
template<typename T>
operator T&() {
return boost::get<T>(it);
}
};
proxy operator[](const std::string& key) {
return proxy(map_[key]);
}
private:
std::map<std::string, MultiType> map_;
};
<强>说明强>
我可以看到Yakk正在尝试类似的事情。我已经在代理中封装了来自MultiType&
的{{1}},然后将工作留给了转换(type-cast)运营商。就是这样。
没有分配的简单map_[key]
可以获得代理。
a[""]
会尝试将double d = a["double"]
转换为proxy
,从而调用double
(我必须对其进行测试,因为我不确定类型扣除是否会起作用它是或将需要更多的工作 - 嗯,它的工作原理!)
AFTERNOTE:从问题和代码中不清楚提供了哪些操作是允许的。我们可以通过更改类型转换运算符的签名来修改proxy::operator double&()
以允许其他操作或更多proxy
,而不是返回readonly
。
允许修改会引发问题:为什么不直接使用const T&
? (从MultiType&
返回)这导致了一个问题:为什么A::operator[]
?
AFTERNOTE#2: boost::variant没有类型转换操作符,并且必须有它的原因。想想这段代码:
class A
运行时异常!我认为最好的解决方案是将MultiType子类化并在那里定义类型转换运算符(同时检查boost::variant::which())。
指派现有名人
int i = a["double"]
...但上述内容只有在我们已经在地图中有一些价值时才有效。
class A { ...
class proxy { ...
template<class T> proxy& operator=(const T& rhs) {
it = rhs; return *this; }
COMPLETE REDISIGN:
class A { ...
A() { map_["pi"] = 3.14; } ...
a["pi"] = 3.1415;
现在我们可以直接使用class MultiType: public boost::variant<int, double, ...> {
public:
template<class T> operator T() {
switch(which()) {
case 0: return boost::get<int>(*this);
case 1: return boost::get<double>(*this);
...
(不使用std::map<std::string, MultiType>
或任何class A
)。