【问题标题】:Output a number that may be one of three types输出一个可能是三种类型之一的数字
【发布时间】:2018-08-12 20:51:19
【问题描述】:

我有一个变量x

它可以是charuint8_tstd::string 类型。

我希望输出数字(不是字符),使用涉及std::cout的相同表达式。这是因为我在生成的代码中使用了这个表达式。

在代码生成时,我目前不知道xcharuint8_t 还是std::string

如果x 的类型为char,则std::cout << x << std::endl 不起作用,因为它将输出字符而不是数字。

如果x 的类型为std::string,则std::cout << +x << std::endl 不起作用。

如果x 的类型为std::stringstd::cout << (typeid(x) == typeid(uint8_t) || typeid(x) == typeid(char) ? +x : x) << std::endl 将不起作用。

如果x 的类型为std::string,则std::cout << (typeid(x) == typeid(uint8_t) || typeid(x) == typeid(char) ? static_cast<int>(x) : x) << std::endl 不起作用。

我知道std::cout 可以通过管道std::hexstd::boolalpha 以各种方式配置,但我知道没有可能的方式配置std::cout 以输出char 作为数字,而不进行转换char 优先。

有没有办法使用反射、运算符重载、模板或其他东西 这样就可以有一个统一的语句来输出x,作为一个数字?

例如,如果 x 为 65,类型为 char,则所需的输出是 65,而不是 A

【问题讨论】:

  • 如果你有一个变量,你就知道它的类型。它怎么可能是三种类型中的一种,而不是它声明时使用的一种类型?我建议您显示minimal reproducible example 来说明问题。
  • 我在编译时知道类型,但在代码生成时不知道。
  • 请说明区别。并向我们​​展示您的代码
  • 代码生成不能生成适当的输出语句,因为它知道类型吗?无论如何,您可以定义一个函数,例如 printMe,并带有 intstring 的重载,只返回参数。让生成器发出 cout << printMe(x)
  • 我写了一个实验性的 Go to C++17 转译器。 github.com/xyproto/go2cpp/tree/so 在根目录下运行go test 时,这是错误:error: no match for ‘operator+’ (operand type is ‘std::__cxx11::string’ {aka ‘std::__cxx11::basic_string<char>’})。编译器当前在生成std::cout 语句时不知道类型。在许多情况下,Go 和 C++17 是相似的,但在这种情况下并非如此。

标签: c++ stdout c++17


【解决方案1】:

只需格式化一个助手并专门化您想要适当自定义的版本。例如:

#include <iostream>

template <typename T>
struct formatter {
    T const& value;
};

template <typename T>
formatter<T> format(T const& value) {
    return formatter<T>{value};
}

template <typename T>
std::ostream& operator<< (std::ostream& out, formatter<T> const& v) {
    return out << v.value;
}

std::ostream& operator<< (std::ostream& out, formatter<char> const& v) {
    return out << int(v.value);
}

template <std::size_t N>
std::ostream& operator<< (std::ostream& out, formatter<char[N]> const& v) {
    return out << '\'' << v.value << '\'';
}


int main() {
    std::cout << "char=" << format('c') << " "
              << "int=" << format(17) << " "
              << "string=" << format("foo") << " "
              << "\n";
}

【讨论】:

  • 谢谢!这正是我想要的。
【解决方案2】:

我猜你是在通用上下文中工作。所以你的基本问题是你需要静态调度。三元运算符 ? : 不提供此功能。它在运行时被评估并且总是调用相同的operator&lt;&lt;

所以你有两个选择:

  1. 使用具有部分特化的辅助类

  2. 使用静态如果。即:

    if constexpr (std::is_integral<decltype(x)>::value)
      std::cout << static_cast<int>(x) << std::endl;
    else
      std::cout << x << std::endl;
    

后者需要 C++17。

【讨论】:

  • 谢谢!这是一个简洁而甜蜜的解决方案。
  • 如果我理解正确,如果有几个变量,比如xyz,很可能还必须有几个if constexpr 表达式,然后是一个final std::endl?
【解决方案3】:

这个解决方案对我有用。它通过使用output 函数以及模板特化和if constexpr 将字符输出为数字:

#include <cstdint>
#include <iostream>
#include <string>

using namespace std::string_literals;

template <typename T> void output(std::ostream& out, T x)
{
    if constexpr (std::is_integral<decltype(x)>::value) {
        out << static_cast<int>(x);
    } else {
        out << x;
    }
}

int main()
{
    char x = 65;
    uint8_t y = 66;
    std::string z = "hi"s;

    // output: A
    std::cout << x << std::endl;

    // output: 65
    output(std::cout, x);
    std::cout << std::endl;

    // output: B
    std::cout << y << std::endl;

    // output: 66
    output(std::cout, y);
    std::cout << std::endl;

    // output: "hi"
    output(std::cout, z);
    std::cout << std::endl;

    return 0;
}

感谢 Dietmar Kühl 和 Marcel 提供的有用答案。

【讨论】:

  • 请注意,这不适用于bool,因为is_integral 认为bool 是不可分割的。我希望使用std:boolalpha 修饰符输出bool
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-02
  • 2019-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-21
  • 1970-01-01
相关资源
最近更新 更多