首页 > 解决方案 > 基于在其参数上调用流输出运算符的能力重载函数

问题描述

我有一个通用函数,它接受两个参数,比较它们,如果它们不相等则打印一条消息。现在,我只有这个相对愚蠢的功能:

template <typename T>
static void AreEqual(const T& expected,
                     const T& actual,
                     const std::string& message = "") {
    if (!(actual == expected)) {
        std::cout << message;
    }
}

多年来,这已经充分发挥了作用。它最常与原语一起调用,但也用于比较较大的用户定义的结构/类。

我想通过提供一个重载来扩展函数,当它们不匹配时打印预期值和实际值,但不会破坏定义operator==但不定义的类的函数operator<<。我的想法是创建一个使用 SFINAE 来禁用重载的重载(如果operator<<丢失)。到目前为止,我已经想出了这个:

template <
    typename T,
    typename = typename std::enable_if_t<
        std::is_same_v<decltype(std::cout << *((T*)nullptr)), decltype(std::cout)>>>
static void AreEqual(const T& expected,
                     const T& actual,
                     const std::string& message = "") {
    if (!(actual == expected)) {
        std::cout << "Expected " << expected << ", got " << actual << ". " << message;
    }
}

这可以编译,但它没有被选择为Tor intstd::string我不知道为什么。我的第一个怀疑是我的论点is_same_v不知何故格式不正确,但如果是这种情况,我不知道如何或如何弄清楚如何解决它。

问题1:这一切是否必要?我可以在没有模板元编程的情况下获得相同的结果吗(最好在坚持使用 C++11 时)

问题 2:如果这是最好的方法,我如何有效地调试我的模板?

标签: c++templatestemplate-meta-programming

解决方案


您可能会执行以下操作:

struct overload_low_priority {};
struct overload_high_priority : overload_low_priority {};


template <typename T>
static auto AreEqualImpl(const T& expected,
                         const T& actual,
                         const std::string& message,
                         overload_high_priority)
-> decltype(std::cout << expected, void()) // SFINAE
{
    if (!(actual == expected)) {
        std::cout << "Expected " << expected << ", got " << actual << ". " << message;
    }
}

template <typename T>
static void AreEqualImpl(const T& expected,
                         const T& actual,
                         const std::string& message,
                         overload_low_priority) // Fallback
{
    if (!(actual == expected)) {
        std::cout << message;
    }
}

template <typename T>
static void AreEqual(const T& expected,
                     const T& actual,
                     const std::string& message = "")
{
    AreEqualImpl(expected, actual, message, overload_high_priority{});
}

推荐阅读