You cannot deactivate a specific function of a class (here std::basic_string) as it is it's interface that clearly (and officially) allow that manipulation. Trying to overload the operator will only mess things up.
Now, you can "wrap" std::basic_string in another class, using private inheritance or composition and then use the public interface as a proxy to the std::basic_string part, but only the functions you want to be usable.
I recommand first replacing you string types with typedefs :
namespace myapp
{
typedef std::string String;
typedef std::wstring UTFString;
}
Then once your application compile fine after having replaced std::string and std::wstring by myapp::String and myapp::UTFString (those are example names), you define the wrapper class somewhere :
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..
};
}
...then, you simply replace those lines :
// 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
... and your example will crash :
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
Here is the full test application code i wrote to prove that (compiled on 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;
}
I think it would cleanly resolve your problem, but you'll have to wrapp all the functions.