C++ 有没有办法确定类是否有重载运算符?

C++ 有没有办法确定类是否有重载运算符?,c++,class,overloading,C++,Class,Overloading,我正在编写一个模板类,其中需要一个方法将元素类打印到stdout中。但是我在编写它时遇到了一个问题-如果cout如果操作符没有重载,那么您的程序就无法编译。这是一个编译时错误,无法将其延迟到运行时 一种解决方法是不使用运算符,而是使用函数指针。如果不支持该操作,则可以将函数指针设置为0,您可以在运行时检测该指针 class A { public: int q; // some data typedef std::function<void(std::ostream&

我正在编写一个模板类,其中需要一个方法将元素类打印到stdout中。但是我在编写它时遇到了一个问题-如果cout如果操作符没有重载,那么您的程序就无法编译。这是一个编译时错误,无法将其延迟到运行时

一种解决方法是不使用运算符,而是使用函数指针。如果不支持该操作,则可以将函数指针设置为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和。对于C++03,您必须使用普通函数指针。

您可以使用一些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

与编译错误相比,您更喜欢异常?这与“快速失败”的重要原则相矛盾。编译错误比异常安全得多。我相信我们需要编写一个故障安全代码。故障安全代码使用的是编译错误,而不是异常。在编译过程中,而不是在运行时,您应该真正解决或让库的用户解决尽可能多的问题。没有办法避免编译错误,您应该在编程时获得这些错误,因为任何人都可能在编写时出错。但编译错误比执行时间/逻辑错误更容易发现和修复。不管怎样,如果不先修复编译错误,就无法继续开发任何东西。我发现检测函数/运算符是否存在/可调用的唯一合法原因是,如果不存在,则提供替代操作,或者在编译时以任何方式做出决定。在运行时延迟任何事情都是胡说八道的。@Testie虽然答案100%正确,但我真的建议您重新考虑您的方法,不要偏爱异常而不是编译错误。@amit我读过这方面的内容,但任务要求我们使用异常。谢谢你的通知。@Testie:这可能取决于应用程序。有时,您无法在编译时知道某些东西是否会/应该工作。但我同意,一般来说,您应该尽可能多地压缩编译时间。为什么*OutputStream*0而不仅仅是std::declval?@iavr旧习惯-修复