How to print result of a compile-time calculation in C++?

有些话、适合烂在心里 提交于 2019-12-01 03:48:07

Here is some code that exploits gcc's diagnostic messages to print values of interest after an assert message. To find the values of interest, you just need to search the error string for T x =:

#include <string>

template <class T, T x, class F>
void transparent(F f) { f(); }


template <bool B>
constexpr void my_assert() { 
    static_assert(B, "oh no");
}

template <int X>
void f() {
    transparent<int, X+7>([]{
        transparent<long, X*X*X>([]{
            my_assert<X+10==-89>(); });});
}

int main() {
//    f<3>();
    f<4>();
//    f<-99>();
}

Here is the error that it got me:

g++ h.cpp -std=c++11 h.cpp: In instantiation of ‘constexpr void my_assert() [with bool B = false]’: h.cpp:16:34: required from ‘f() [with int X = 4]::__lambda0::__lambda1’ h.cpp:15:35: required from ‘struct f() [with int X = 4]::__lambda0::__lambda1’ h.cpp:16:38: required from ‘f() [with int X = 4]::__lambda0’ h.cpp:14:28: required from ‘struct f() [with int X = 4]::__lambda0’ h.cpp:16:41: required from ‘void f() [with int X = 4]’ h.cpp:21:10: required from here h.cpp:9:5: error: static assertion failed: oh no static_assert(B, "oh no"); ^ h.cpp:4:6: error: ‘void transparent(F) [with T = long int; T x = 64l; F = f() [with int X = 4]::__lambda0::__lambda1]’, declared using local type ‘f() [with int X = 4]::__lambda0::__lambda1’, is used but never defined [-fpermissive] void transparent(F f) { f(); } ^ h.cpp:4:6: error: ‘void transparent(F) [with T = int; T x = 11; F = f() [with int X = 4]::__lambda0]’, declared using local type ‘f() [with int X = 4]::__lambda0’, is used but never defined [-fpermissive]

Note that bolded parts

My VC++ code that print, during compilation, the value of as many compile time constants as you like (e.g. sizeof structures) and continue compiling without error:

// cpptest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
//#define VALUE_TO_STRING2(x) #x
//#define VALUE_TO_STRING(x) VALUE_TO_STRING2(x)


#define TO_STRING(x) #x
#define FUNC_TEMPLATE_MSG(x,y) "[" x "]""["TO_STRING(y)"]"

template<unsigned int N,unsigned int M> 
int printN()
{ 
#pragma message(FUNC_TEMPLATE_MSG(__FUNCSIG__ ,1))

    return 0;
};



struct X {
    char a[20];
    int b;
};
struct Y {
    char a[210];
    int b;
};

int _tmain(int argc, _TCHAR* argv[])
{
printN<sizeof(X),__COUNTER__>();
printN<sizeof(Y),__COUNTER__>();
//..as many compile time constants as you like
}

Sample output produced by VC++2010. The target value is the first function template parameter value (0x18 and 0xd8 in the example) which VC++ oddly chose to output as hexadecimal value!!

1>------ Build started: Project: cpptest, Configuration: Release Win32 ------
1>  cpptest.cpp
1>  [int __cdecl printN<0x18,0x0>(void)][1]
1>  [int __cdecl printN<0xd8,0x1>(void)][1]
1>  Generating code
1>  Finished generating code
1>  cpptest.vcxproj -> c:\work\cpptest\Release\cpptest.exe
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

The major technique used here is that a during each function template instantiation, the #pragma message() directive is invoked once. The Microsoft specific macro __FUNCSIG__ can display the signature of the containing function and thus the integer value used in each specific instantiation of the function template. Giving COUNTER as the second template parameter is to make sure 2 integers of the same value are still considered different. The 1 in the #pragma directive is of no use here but can be used as an identifier in case we have more than 1 such directive and the output window is full of messy messages.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!