小伙伴们,我在做科研的时候遇到一个问题,是否可以在编译时输出评估值?编译器肯定会在编译时评估表达式,关键是我们如何在编译期间输出评估值?一种方法是强制错误,但似乎不是很优雅。如果我想使用 TMP,可以吗?谢谢。
3 回答
假设您想查看整数常量表达式的值,查看该值以进行调试的一种简单方法是使用该值创建一个错误。例如:
template <int> struct constexpr_debugger;
int main() {
const int i0(4), i1(17);
constexpr_debugger<i0 + i1> debug;
}
当我编译这段代码时,我收到了消息
constexpr_debugger.cpp: In function ‘int main()’:
constexpr_debugger.cpp:5:37:error: aggregate ‘constexpr_debugger<21> debug’ has incomplete type and cannot be defined
constexpr_debugger<i0 + i1> debug;
^
如果您对这些值感兴趣,但仍想编译代码,我知道的最佳方法是创建一条警告消息,例如基于未使用的变量。由于标准从不要求警告,因此它在一定程度上取决于编译器和显示警告时使用的标志。用gcc和clang对其进行测试表明,如果简单地定义了上述类模板,编译器很遗憾不会显示模板参数的值。以下代码显示[当前]编译器在诊断中报告的内容有所不同:
template <int>
void constexpr_debugger()
{
int debug;
}
int main() {
const int i0(4), i1(17);
constexpr_debugger<i0 + i1>();
}
gcc 提到的函数包括它的模板参数,因此,当警告debug
未使用时,需要的值。clang 也警告debug
过,但没有提到问题发生的模板实例化。您将需要与您正在使用的编译器一起使用的那种形式的东西(可能需要根据您正在使用的编译器版本进行定制)。
从 C++11 开始,constexpr
可用于启用在编译时评估该表达式
例子 :
constexpr int sqr(int x)
{
return x*x;
}
int a[sqr(4)]; //Compiles with C++11 and a has 16 elements.
要显示评估的表达式,请使用模板元编程
template<unsigned int n>
struct dummy ;
int main() {
char<dummy1<dummy<1 + 55-2>::dummy2>()); //Obliviously wrong
return 0;
}
来自编译器的错误:
error: incomplete type 'dummy<54u>' used in nested name specifier
如果您不喜欢使用编译错误或警告,您可以将类型信息放入目标文件中的符号中。以下程序将为编译时间列表执行此操作。
// Just define the types we need to construct lists.
template <typename Head, typename Tail> struct Cons {};
struct Nil {};
// This is what you want to output.
using MyOutput = Cons<int, Cons<float, Cons<char, Nil>>>;
// Template function declaration.
template <typename TheOutput>
void MyOutputFunc () {}
// Explicitly instantiate the template function with the desired output.
template void MyOutputFunc<MyOutput> ();
检索输出将是编译器,也可能是特定于操作系统的。下面为 Linux 上的 g++ 演示了这一点。
$ g++ -c -std=c++11 a.cpp
$ nm a.o | grep MyOutputFunc
0000000000000000 W _Z12MyOutputFuncI4ConsIiS0_IfS0_Ic3NilEEEEvv
$ nm a.o | grep MyOutputFunc | cut -d ' ' -f3 | c++filt
void MyOutputFunc<Cons<int, Cons<float, Cons<char, Nil> > > >()
您可以通过将整数包装成如下类型来输出整数:
template <typename T, T value>
struct WrapValue {};
using MyOutput = WrapValue<int, 15>;
这对于检索各种支持信息比调试更有用。例如,我对这种方法的用例与一些微控制器软件的配置选项有关,编译时输出是模板程序如何将配置选项映射到 EEPROM 存储器。