类模板:防止分配<other> type </other>

时间:2013-02-27 09:10:33

标签: c++ templates visual-c++ private

我有一个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=的专用版本,它仍然可以使用。我想避免这种情况!

2 个答案:

答案 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)

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

  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;
    
  3. 声明运营商私有在VS2012之前的Visual Studio中不起作用,因为VS不尊重私有运营商(已知错误): http://connect.microsoft.com/VisualStudio/feedback/details/649496/visual-c-doesnt-respect-the-access-modifier-for-operator-member-function-templates 然而,如果那些运算符没有实现(它们不应该),链接器会抱怨。