0

我有一个CFixedLengthString类模板,只有数据成员。数据成员的大小由模板类型参数确定。

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>&);

而且,当然,将其设为 private,因此如果<20>转换为<non-20>. 但是,令我惊讶的是,编译器并没有抱怨!它允许调用这个私人运营商!

如果<N>被复制到<N>,它调用正常的赋值操作符。如果<N>被复制(分配)给<M>编译器,则调用此专用操作符。

但是为什么编译器允许在这种情况下调用私有(以及受保护)?我正在使用 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=,它仍然可以工作。我想避免这种情况!

4

2 回答 2

1

对于您的情况,您可以删除有operator const char*()利于访问器函数的访问器函数,例如c_ptr()与 std::string 类似的解决方案,用于通过 c_str() 转换为 char*

另一种解决方案是将赋值设为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");
于 2013-02-27T09:17:25.097 回答
0

有几种方法可以实现这一点。

  1. operator const char*可能在某些地方很方便,但显然它会在您不希望它的某些地方触发。考虑删除它,用类似于std::string::c_str()或制作它的函数替换它explicit(仅限 C++11)。
  2. 您可以为其他不起作用的类型显式声明转换构造函数 - 因为它们是私有的(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-尊重访问修饰符for-operator-member-function-templates 然而,如果这些操作符没有实现(他们不应该) ,链接器会抱怨。

于 2013-02-27T10:50:52.300 回答