是否只能使用类操作符进行转换?

时间:2008-10-16 18:54:13

标签: c++ compiler-construction casting

一种随意的问题......

我正在寻找的是一种表达强制转换操作的方法,该操作使用我正在转换的类实例的已定义运算符,如果没有为该类型定义的强制转换运算符,则会生成编译时错误。所以,例如,我正在寻找的是:

template< typename RESULT_TYPE, typename INPUT_TYPE >
RESULT_TYPE operator_cast( const INPUT_TYPE& tValue )
{
    return tValue.operator RESULT_TYPE();
}

// Should work...
CString sString;
LPCTSTR pcszString = operator_cast< LPCTSTR >( sString );

// Should fail...
int iValue = 42;
DWORD dwValue = operator_cast< DWORD >( iValue );

有趣的注意事项:上面的代码崩溃了VS2005 C ++编译器,并且由于我猜测它是编译器错误而无法在VS2008 C ++编译器中正确编译,但希望能够证明这一点。

有人知道有什么方法可以达到这个效果吗?

编辑:更多理由,解释为什么你可以使用它。假设你有一个封装类,它应该封装或抽象一个类型,然后你将它转换为封装类型。您可以使用static_cast&lt;&gt;,但是当您希望它失败时可能会有效(即:编译器选择一个允许转换为您要求的类型的运算符,当您因为该运算符不存在而需要失败时)

不可否认,这是一个不常见的情况,但令人讨厌的是我无法准确地表达我希望编译器在封装函数中做什么......因此这里的问题。

4 个答案:

答案 0 :(得分:3)

您发布的代码与Cameau compiler一起使用(这通常表明它是有效的C ++)。

如您所知,有效的强制转换包含不超过一个用户定义的强制转换,因此我想到的一个可能的解决方案是通过在强制转换模板中定义新类型并添加static assert来添加另一个用户定义的强制转换没有从新类型到结果类型的转换(使用boost is_convertible),但是这不区分强制转换操作符和强制转换构造函数(ctor有一个参数)并且允许进行其他强制转换(例如{ {1}}到void*)。我不确定在强制转换操作符和强制转换构造函数之间区分是正确的要做的事情,但这就是问题所说的。

经过几天的考虑,它击中了我,你可以简单地获取演员的地址。由于C ++指向成员语法的毛茸茸的指针,这说起来容易做起来难以理解(我花了比预期更长的时间才能做到正确)。我不知道这是否适用于VS2008,我只在Cameau上检查过它。

bool

编辑:我有机会在VS2005和VS2008上测试它。我的发现与原版海报不同。

  • 在VS2008上,原始版本似乎工作正常(我的也是如此)。
  • 在VS2005上,原始版本只会在提供编译错误后从内置类型(例如,将int转换为int)中崩溃编译器,这对我来说似乎并不是很糟糕,我的版本似乎在所有情况下都适用。

答案 1 :(得分:1)

使用标记为explicit的转换构造函数是阻止编译器允许隐式转换类型初始化包装类的方法。

答案 2 :(得分:1)

由于模板相关的编译器错误消息通常很难解开,如果您不介意指定每个转换,您也可以通过提供默认模板定义让编译器在失败的情况下发出更具指导性的消息。这使用的事实是编译器只会尝试在实际调用的模板中编译代码。

#include <string>

// Class to trigger compiler warning   
class NO_OPERATOR_CONVERSION_AVAILABLE
{
private:
   NO_OPERATOR_CONVERSION_AVAILABLE(){};
};

// Default template definition to cause compiler error
template<typename T1, typename T2> T1 operator_cast(const T2&)
{
   NO_OPERATOR_CONVERSION_AVAILABLE a;
   return T1();
}

// Template specialisation
template<> std::string operator_cast(const std::string &x)
{
   return x;
}

答案 3 :(得分:0)

听起来你想要模板专业化,就像这样:

/* general template */
template<typename T1, typename T2> T1 operator_cast(const T2 &x);

/* do this for each valid cast */
template<> LPCTSTR operator_cast(const CString &x) { return (LPCTSTR)x; }

编辑:正如另一篇文章所述,如果执行了不支持的强制转换,您可以在通用版本中添加一些内容,以便为您提供更有用的错误消息。