【问题标题】:Is there a way to find out if a class has an overloaded operator?有没有办法找出一个类是否有一个重载的运算符?
【发布时间】:2014-04-08 08:52:39
【问题描述】:

我正在编写一个模板类,我需要一个方法将元素类打印到stdout。但是我在编写它时遇到了问题 - 如果我的元素类中没有定义或重载 cout <<operator const char*() 怎么办?

有没有办法找出它可能会抛出异常而不会出现编译错误?

【问题讨论】:

  • 更喜欢出现异常而不是编译错误?这与“快速失败”的重要原则相矛盾。编译错误比异常安全得多。
  • 我相信我们需要编写“故障安全”代码。
  • 故障安全代码使用的是编译错误而不是异常。您应该真正解决(或让您的库的用户)在编译期间而不是在运行时解决尽可能多的问题。
  • 没有办法避免编译错误,无论如何你都应该在编程时得到它们,因为任何人都可能在编写时出错。但是编译错误比执行时间/逻辑错误更容易发现和修复。而且无论如何,如果你不先修复编译错误,就没有办法继续开发任何东西。
  • 我发现检测函数/运算符是否存在/可调用的唯一正当理由是在编译时提供替代操作(或以任何方式做出决定) 。为运行时间延迟任何东西都是无稽之谈。

标签: c++ class overloading


【解决方案1】:

如果操作符没有被重载,你的程序就不能编译。这是一个编译时错误,无法将其延迟到运行时。

一种解决方法是不使用运算符,而是使用函数指针。如果不支持该操作,则可以将函数指针设置为 0,您可以在运行时检测到。

class A {
public:
    int q; // some data

    typedef std::function<void(std::ostream& os, const A&)> PrinterFunc;
    PrinterFunc func;

    friend std::ostream& operator<<(std::ostream& os, const A& a) {
        if(!a.func) {
            throw "Not supported";
        }
        func(os,a);
        return os;
    }
};

A a;
a.func = [](std::ostream& os, const A& a) { os << "hello " << a.q; }
std::cout << a << std::endl; // will print

A b;
std::cout << b << std::endl; // will throw

此示例使用 C++11 和 &lt;functional&gt;。对于 C++03,您必须使用“普通”函数指针。

【讨论】:

  • @Testie 虽然答案是 100% 正确,但我真的建议您重新考虑您的方法,不要偏向于编译错误。
  • @amit 我读到过,但任务要求我们使用异常。不过感谢您的通知。
  • @Testie:这可能取决于应用程序。有时您无法在编译时知道某些东西是否会/应该起作用。但我同意,一般来说你应该尽可能多地推动编译时间。
【解决方案2】:

您可以使用一些 SFINAE 来测试是否存在(格式化的)输出运算符:

#include <iostream>

// HasFormattedOutput
// ============================================================================

namespace HasFormattedOutput {

    namespace Detail
    {
        struct Failure{};
    }

    template<typename OutputStream, typename T>
    Detail::Failure operator << (OutputStream&, const T&);

    template<typename OutputStream, typename T>
    struct Result : std::integral_constant<
        bool,
        ! std::is_same<
            decltype(std::declval<OutputStream&>() << std::declval<T>()),
            Detail::Failure
        >::value
    > {};
} // namespace HasFormattedOutput

template <typename T, typename OutputStream = std::ostream>
struct has_formatted_output : std::conditional<
    HasFormattedOutput::Result<OutputStream, T>::value,
    std::true_type,
    std::false_type>::type
{};

// Test
// ============================================================================

struct X {};
int main() {
    std::cout.setf(std::ios_base::boolalpha);
    std::cout << has_formatted_output<const char*>() << '\n';
    std::cout << has_formatted_output<X>() << '\n';
}

(C++11)

【讨论】:

  • 为什么是(*(OutputStream*)0) 而不仅仅是std::declval&lt;OutputStream&amp;&gt;()
  • @iavr 旧习惯 - 已修复
猜你喜欢
  • 2011-01-16
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
  • 2013-08-12
  • 1970-01-01
  • 2017-09-05
  • 1970-01-01
相关资源
最近更新 更多