【问题标题】:enable_if and conversion operator?enable_if 和转换运算符?
【发布时间】:2011-03-05 19:24:18
【问题描述】:

有没有机会将enable_if 与类型转换运算符一起使用?看起来很棘手,因为返回类型和参数列表都是隐式的。

【问题讨论】:

  • C++0x 通过默认参数使其成为可能:template<typename T, typename = typename enable_if<Cond>::type> operator T() { ... }

标签: c++ boost casting operator-overloading enable-if


【解决方案1】:

根据我所做的小研究(并忽略 Johannes 的 c++0x 评论),我的回答是这取决于您想要 enable_if 的用途。如果您希望 T 类型的转换操作存在或不存在 T ,那么答案似乎是否定的,在 C++03 中没有办法(正如 Ugo 所说)。但是,如果您需要 enable_if 根据 T 的类型更改运算符的 行为,那么可以,有一种解决方法是调用启用的辅助函数(称为 to<T>正如马修建议的那样)。

#include<iostream>
#include<boost/utility/enable_if.hpp>
#include<boost/type_traits/is_class.hpp>

struct B{
    B(const B& other){}
    B(){}
};

struct A{
    template<class T>
    T to(typename boost::enable_if_c<not boost::is_class<T>::value, void*>::type = 0){
        std::clog << "converted to non class" << std::endl;
        return T(0);
    }
    template<class T>
    T to(typename boost::enable_if_c<boost::is_class<T>::value, void*>::type = 0){
        std::clog << "conveted to class" << std::endl;
        return T();
    }
    template<class T>
    operator T(){
        return to<T>();
    }
};

int main(){
    A a;
    double d = (double)a; // output: "converted to non class"
    B b = (B)(a); // output: "converted to class"
    return 0;
}

为了记录,我对此感到沮丧好几天,直到我意识到我想要 enable_if 不是为了 SFINAE,而是为了编译时行为改变。您可能还会发现这也是您需要enable_if 的真正原因。只是一个建议。

(请注意这是针对C++98时代的答案)

【讨论】:

  • 您说操作“存在与否”不可能取决于类型 T。但是,如果您留下一个 to() ,则相应的转换将失败并出现编译时错误,这是期望的行为。我错过了什么吗?
  • 是的,我认为你是对的,但这是问题背后的意图吗?
  • 也许我误解了你的回答,你说“这在 c++03 中是不可能的”,但随后你展示了它是如何可能的。
【解决方案2】:

其实我已经找到了办法;我们使用一个私有的、未使用的类来标记一个不应该存在的转换,并且我们使用boost::mpl::if_ 来选择是生成一个到 NoConversion 还是到所需类型的转换。

class A {
    class NoConversion { };
    template<class B> operator typename boost::mpl::if_<Cond, B, NoConversion>::type() const;
}

【讨论】:

    【解决方案3】:

    虽然我能理解这个问题的理论兴趣,但我个人尽量避免使用转换运算符。

    我唯一使用过的一致性是转换为伪布尔值(使用安全布尔成语),用于智能指针或代理,并且如前所述,我使用了一个技巧来实际阻止完整的布尔语义.. .

    如果我想促进转换,我更喜欢以下方式:

    template <class T>
    T to() const;
    

    它不受转换运算符的限制(在签名方面)并且需要显式调用,只是因为它更清晰一些。

    【讨论】:

      【解决方案4】:

      dixit documentation:
      似乎没有办法为转换运算符指定启用器。然而,转换构造函数可以将启动器作为额外的默认参数。

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-04
      • 1970-01-01
      • 2012-01-27
      • 2013-08-25
      • 1970-01-01
      • 2014-10-01
      • 2010-10-27
      • 1970-01-01
      相关资源
      最近更新 更多