有点随机的问题...

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

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<>,但是当您希望它失败时这可能会起作用(即:当您因为该运算符不存在而希望失败时,编译器会选择一个允许转换为您要求的类型的运算符)。

诚然,这是一种不常见的情况,但令人烦恼的是我无法准确表达我希望编译器在封装函数中执行的操作......因此这里的问题。

有帮助吗?

解决方案

您发布的代码适用于 卡莫编译器 (这通常很好地表明它是有效的 C++)。

如您所知,有效的强制转换由不超过一个用户定义的强制转换组成,因此我想到的一种可能的解决方案是通过在强制转换模板中定义新类型并具有 静态断言 没有从新类型到结果类型的转换(使用 boost is_convertible),但是这并不区分强制转换运算符和强制转换构造函数(具有一个参数的构造函数),并且允许进行其他强制转换(例如 void*bool)。我不确定区分强制转换运算符和强制转换构造函数是否是最重要的 正确的 要做的事情,但这就是问题所指出的。

经过几天的思考,我突然想到,你可以简单地获取演员操作员的地址。由于 C++ 复杂的指向成员语法的指针,这说起来容易做起来难(我花了比预期更长的时间才把它做好)。我不知道这是否适用于VS2008,我只在Cameau上检查过。

template< typename Res, typename T>
Res operator_cast( const T& t )
{
    typedef Res (T::*cast_op_t)() const;
    cast_op_t cast_op = &T::operator Res;
    return (t.*cast_op)();
}

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

  • 在 VS2008 上,原始版本似乎工作正常(就像我的一样)。
  • 在 VS2005 上,原始版本仅在从内置类型(例如在提供编译错误后将 int 转换为 int),这对我来说似乎并没有那么糟糕,我的版本似乎在所有情况下都有效。

其他提示

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

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

#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;
}

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

/* 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; }

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top