有没有办法取消定义chars和wchar_t的字符串和字符串的+ =?
基本上我想避免以下错误:
int age = 27;
std::wstring str = std::wstring(L"User's age is: ");
str += age;
std::string str2 = std::string("User's age is: ");
str2 += age;
上面的代码会将ascii字符27添加到字符串而不是数字27。
我显然知道如何解决这个问题,但我的问题是:在这种情况下如何产生编译错误?
注意:您可以在std :: string和int上覆盖+ =以正确格式化字符串,但这不是我想要做的。我想在这些操作数上完全禁止这个操作符。
答案 0 :(得分:9)
你无法停用某个类的特定函数(此处为std :: basic_string),因为它的界面明显(并且正式)允许该操作。试图使操作员超载只会搞砸。
现在,你可以使用私有继承或组合将“std :: basic_string”包装在另一个类中,然后使用公共接口作为std :: basic_string部分的代理,但只有你希望可以使用的功能。
我建议先用typedef替换字符串类型:
namespace myapp
{
typedef std::string String;
typedef std::wstring UTFString;
}
然后,一旦你的应用程序在用myapp :: String和myapp :: UTFString(这些是示例名称)替换std :: string和std :: wstring之后编译正常,你可以在某处定义包装类:
namespace myapp
{
/** std::basic_string with limited and controlled interface.
*/
template< class _Elem, class _Traits, class _Ax >
class limited_string
{
public:
typedef std::basic_string< _Elem , _Traits, _Ax > _String; // this is for easier writing
typedef limited_string< _Elem, _Traits, _Ax > _MyType; // this is for easier writing
private:
_String m_string; // here the real std::basic_string object that will do all the real work!
public:
// constructor proxies... (note that those ones are not complete, it should be exactly the same as the original std::basic_string
// see some STL docs to get the real interface to rewrite)
limited_string() : m_string {}
limited_string( const _MyType& l_string ) : m_string( l_string.m_string ) {}
limited_string( const _Elem* raw_string ) : m_string( raw_string ) {}
//... etc...
// operator proxies...
_MyType& operator= ( const _MyType& l_string )
{
m_string = l_string.m_string;
}
// etc...
// but we don't want the operator += with int values so we DON'T WRITE IT!
// other function proxies...
size_t size() const { return m_string.size(); } // simply forward the call to the real string!
// etc...you know what i mean...
// to work automatically with other STL algorithm and functions we add automatic conversion functions:
operator const _Elem*() const { return m_string.c_str(); }
// etc..
};
}
...然后,您只需替换这些行:
// instead of those lines...
//typedef std::string String;
//typedef std::wstring UTFString;
// use those ones
typedef limited_string< char, std::char_traits<char>, std::allocator<char> > String; // like std::string typedef
typedef limited_string< wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > UTFString; // like std::wstring typedef
...你的例子会崩溃:
error C2676: binary '+=' : 'myapp::UTFString' does not define this operator or a conversion to a type acceptable to the predefined operator
error C2676: binary '+=' : 'myapp::String' does not define this operator or a conversion to a type acceptable to the predefined operator
这是我编写的完整测试应用程序代码,用于证明(在vc9上编译):
#include <string>
#include <iostream>
namespace myapp
{
/** std::basic_string with limited and controlled interface.
*/
template< class _Elem, class _Traits, class _Ax >
class limited_string
{
public:
typedef std::basic_string< _Elem , _Traits, _Ax > _String; // this is for easier writing
typedef limited_string< _Elem, _Traits, _Ax > _MyType; // this is for easier writing
private:
_String m_string; // here the real std::basic_string object that will do all the real work!
public:
// constructor proxies... (note that those ones are not complete, it should be exactly the same as the original std::basic_string
// see some STL docs to get the real interface to rewrite)
limited_string() : m_string {}
limited_string( const _MyType& l_string ) : m_string( l_string.m_string ) {}
limited_string( const _Elem* raw_string ) : m_string( raw_string ) {}
//... etc...
// operator proxies...
_MyType& operator= ( const _MyType& l_string )
{
m_string = l_string.m_string;
}
// etc...
// but we don't want the operator += with int values so we DON'T WRITE IT!
// other function proxies...
size_t size() const { return m_string.size(); } // simply forward the call to the real string!
// etc...you know what i mean...
// to work automatically with other STL algorithm and functions we add automatic conversion functions:
operator const _Elem*() const { return m_string.c_str(); }
// etc..
};
// instead of those lines...
//typedef std::string String;
//typedef std::wstring UTFString;
// use those ones
typedef limited_string< char, std::char_traits<char>, std::allocator<char> > String; // like std::string typedef
typedef limited_string< wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > UTFString; // like std::wstring typedef
}
int main()
{
using namespace myapp;
int age = 27;
UTFString str = UTFString(L"User's age is: ");
str += age; // compilation error!
std::wcout << str << std::endl;
String str2 = String("User's age is: ");
str2 += age; // compilation error!
std::cout << str2 << std::endl;
std::cin.ignore();
return 0;
}
我认为它会干净地解决你的问题,但你必须包装所有的功能。
答案 1 :(得分:8)
大多数源代码管理系统允许您在签入期间对代码运行完整性检查。因此,您可以设置测试以执行验证并拒绝签入失败:
示例:
测试脚本:
#!/bin/tcsh
# Pass the file to test as the first argument.
echo "#include <string>\
void operator+=(std::string const& , int const&);\
void operator+=(std::string const& , int);"\
| cat - $1 \
| g++ -c -x c++ - >& /dev/null
echo $status
此脚本伪造了上面两个运算符的添加(实际上没有更改源)。即使原始代码编译,这也会导致使用operator + with strings和char失败。
注意:操作员+ =从litb偷来的想法。谁已经删除了他的例子。但信用到期。
答案 2 :(得分:3)
1)创建一个自己的字符串类,继承/包含std::string
。
2)在此类中重载operator+=(int val)
并将其设为私有。
3)将此类用于所有字符串操作。
这会使编译器在执行以下操作时标记错误:
MyString str;
str += 27;
答案 3 :(得分:3)
没有简单的方法来阻止它,但有一种简单的方法可以找到它。编写一个使用此运算符的小程序,然后查看运算符的错位符号+ =您想要禁止。此符号是唯一的字符串。作为自动化测试的一部分,使用DUMPBIN(或等效的Linux / Mac工具)检查目标文件中是否存在这个受损的符号。