I am trying to create a "value" template class, where additional properties can be assign to it easily.
Properties are stored instd::map<std::string, std::string>
, and operator[]
has been overloaded to provide quick access to them.
#if ! defined __VALUE_H__
#define __VALUE_H__
#include <string>
#include <map>
namespace Algorithm
{
template<typename TValueType>
class CValue
{
public:
CValue(const TValueType& Value) :
m_Value(Value)
{
}
~CValue()
{
}
CValue(const CValue& Source) :
m_Value(Source.m_Value),
m_mssProperties(Source.m_mssProperties)
{
}
CValue& operator=(const CValue& Source)
{
if (this != &Source)
{
m_Value = Source.m_Value;
m_mssProperties = Source.m_mssProperties;
}
return *this;
}
CValue& operator=(const TValueType& Source)
{
m_Value = Source;
return *this;
}
std::string& operator[](const std::string& sPropertyName)
{
return m_mssProperties[sPropertyName];
}
std::string operator[](const std::string& sPropertyName) const
{
std::map<std::string, std::string>::const_iterator iter;
iter = m_mssProperties.find(sPropertyName);
return ((iter!=m_mssProperties.end()) ? iter->second : "");
}
operator TValueType () const
{
return m_Value;
}
private:
TValueType m_Value;
std::map<std::string, std::string> m_mssProperties;
};
};
#endif //__VALUE_H__
Why does when I invoke operator[] with string laterals, MSVC2008 complains on overloads ambiguity.
#include <string>
#include "Value.h"
int main()
{
std::string valName = "XX";
std::string valProp = "YY";
Algorithm::CValue<int> obj(valName, 2);
obj[valProp] = "ZZ";
obj["AA"] = "BB"; // compiler error
return 0;
}
Compiler error:
1>------ Build started: Project: TemplateHell, Configuration: Debug Win32 ------
1>Compiling...
1>TemplateHell.cpp
1>c:\documents and settings\yeen-fei.lim\my documents\visual studio 2008\projects\templatehell\templatehell.cpp(13) : error C2666: 'Algorithm::CValue<TValueType>::operator []' : 3 overloads have similar conversions
1> with
1> [
1> TValueType=int
1> ]
1> c:\documents and settin开发者_运维知识库gs\yeen-fei.lim\my documents\visual studio 2008\projects\templatehell\value.h(146): could be 'std::string Algorithm::CValue<TValueType>::operator [](const std::string &) const'
1> with
1> [
1> TValueType=int
1> ]
1> c:\documents and settings\yeen-fei.lim\my documents\visual studio 2008\projects\templatehell\value.h(134): or 'std::string &Algorithm::CValue<TValueType>::operator [](const std::string &)'
1> with
1> [
1> TValueType=int
1> ]
1> or 'built-in C++ operator[(int, const char [3])'
1> while trying to match the argument list '(Algorithm::CValue<TValueType>, const char [3])'
1> with
1> [
1> TValueType=int
1> ]
1>Build log was saved at "file://c:\Documents and Settings\yeen-fei.lim\My Documents\Visual Studio 2008\Projects\TemplateHell\Debug\BuildLog.htm"
1>TemplateHell - 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Edit:
When i remove implicit conversion-operator from the code, it will compile without error. But it makes no sense for me because it is never used so far.
obj["AA"]
... have you seen a similar construct before? There is an old C obfuscation trick where you take the array and the index and reverse them in the expression as a[b]
is the same as *(a + b)
which is the same as b[a]
. In the cast overload in this case, you are returning a integer. The other element of the call is a character array. This confuses the compiler as it doesn't know if this is you trying to get element obj
of "AA"
, or if you want the overloaded operator. You can see this in the output of the following program:
#include <iostream>
#include <string>
using namespace std;
template <typename T>
class Val {
T const ret;
public:
Val(T r) : ret(r) {}
operator T () const {
return ret;
}
};
int main()
{
Val<int> v(3);
cout << v["abcd"] << endl;
return 0;
}
d
Consider the following:
#include <iostream>
#include <string>
using namespace std;
template <typename T>
class Val {
T const ret;
public:
Val(T r) : ret(r) {}
operator T () const {
return ret;
}
string operator[](string const &) const {
return string("Hi!");
}
};
int main()
{
Val<int> v(3);
cout << v["Hello!"] << endl;
return 0;
}
This gives a similar error. Change Val<int>
to Val<double>
and the problem magically goes away (you can't index an array with a double; no confusion).
The solution in this case is to create another overload: string operator[](char const *) const
. This gets rid of the confusion.
obj["AA"] = "BB";
"AA" is of type char* and not std::string.
Why does when I invoke operator[] with string laterals, MSVC2008 complains on overloads ambiguity.
Because it is ambiguous. You need to change the signature of the function/operator. Make the operators look like this:
std::string& operator[](const std::string& sPropertyName);
std::string const& operator[](const std::string& sPropertyName) const;
Instead of returning ""
when the key is missing in the map, return a reference to some empty const std::string
instance.
精彩评论