我有一个CFixedLengthString
类模板,只有数据成员。 datamember的大小由模板类型参数确定。
template<size_t _Length>
class CFixedLengthString
{
private:
char Buffer[_Length];
public:
// Has constructors, conversion operators etc.
// Listing the important ones
operator const char*();
operator = (const CFixedLengthString&);
operator = (const char*);
};
自动转换是为了方便起见。例如:
CFixedLengthString<10> buf;
buf = "SomeString";
strlen(buf);
但是这种便利也可以让以下成功:
CFixedLengthString<10> buf1;
CFixedLengthString<20> buf2;
buf1 = buf2;
此处buf2
通过隐式转换运算符转换为const char*
,operator=
通过const char*
调用。因此<20>
转换为<10>
。
这里的重要内容。
为此,我编写了一个赋值运算符,它采用不同大小的CFixedLengthString
。
template<size_t _TOtherSize>
void operator=(const CFixedLengthString<_TOtherSize>&);
当然,将其设为私有,因此如果将<20>
转换为<non-20>
,则会导致编译错误。但令我惊讶的是,编译器并没有抱怨!它允许调用这个私人运营商!
如果<N>
被复制到<N>
,则会调用正常的分配操作数。如果<N>
被复制(分配)给<M>
编译器,则调用此专用的opeartor。
但是为什么编译器允许在这种情况下调用private(以及protected)?我正在使用VC2008编译器。我正在寻找这个编译器的解决方案。
现在,我在这个专门的函数体内编写了一个静态断言(为了禁止这种错误的转换)。
修改 所有回复都表示赞赏。我唯一的问题是:
private
区域的专业版可以调用?我们都使用私有,仅声明函数,delete
属性和防御性编程的其他方面。我也试图这样做。但编译器允许调用私有函数!
编辑2: 示例代码:
template<size_t SIZE>
class FixedString
{
public:
operator const char*();
void operator =(const char*);
void operator =(const FixedString&);
// Disallow
private:
template<size_t OTHERSIZE>
void operator=(const FixedString<OTHERSIZE>&);
};
int main()
{
FixedString<10> buf1;
FixedString<20> buf2;
buf2 = buf1; // NO ERROR!!
}
如果删除operator=
的专用版本,它仍然可以使用。我想避免这种情况!
答案 0 :(得分:1)
对于您的情况,您可以删除operator const char*()
以支持访问者函数,例如c_ptr()
,这是std :: string的类似解决方案,用于通过c_str()
另一种解决方案是将赋值operator = (const char*);
设为私有,并从char *中定义显式构造函数,以便只有在需要时才能在类型之间显式转换:
class CFixedLengthString
{
public:
explicit CFixedLengthString( char* str ) { *this = str );
private:
operator = (const char*);
};
...
CFixedLengthString<10> buf1;
CFixedLengthString<20> buf2;
buf1 = CFixedLengthString<10>(buf2);
此当前示例将限制您:
CFixedLengthString<10> buf1( "string" );
buf1 = CFixedLengthString<10>("string");
答案 1 :(得分:0)
有几种方法可以实现这一目标。
operator const char*
可能在某些地方很方便,但显然它会在你不想要的地方被触发。考虑删除它,将其替换为类似于std::string::c_str()
的函数或使其成为explicit
(仅限C ++ 11)。您可以为其他无效的类型显式声明转换构造函数 - 因为它们是私有的(C ++ 03)或已删除(仅限C ++ 11)。
template <class T>
CFixedLengthString& operator=(T const&) = delete;
//or delete just other FixedLengthStrings:
template <size_t L> // _Length is a reserved identifier, do't use it!
CFixedLengthString& operator=(CFixedLengthString<L> const&) = delete;
声明运营商私有在VS2012之前的Visual Studio中不起作用,因为VS不尊重私有运营商(已知错误): http://connect.microsoft.com/VisualStudio/feedback/details/649496/visual-c-doesnt-respect-the-access-modifier-for-operator-member-function-templates 然而,如果那些运算符没有实现(它们不应该),链接器会抱怨。