如何在C ++中编译时打印一个完整的模板参数

时间:2009-12-01 13:04:47

标签: c++ templates

假设我已经实现了这样的模板类:

template <size_t N> class C 
{
     void f()
     {
        // print out N here?
     }
};

我希望编译器编译像

这样的子句
C<20> c;

它会打印出一条消息

“C类模板化为N = 20”

我尝试使用#pragma和static_assert是徒劳的。

问题在于

  1. 使用#pragma和static_assert,我无法将一个积分(20在这里)嵌入到一条消息中;
  2. 使用预处理器,现在为时尚早 N不代替20 爱好。
  3. 有没有办法或没办法?

    感谢。

7 个答案:

答案 0 :(得分:4)

您可以添加一个构建后步骤,在模板的所有编译完成后查找输出二进制文件中的所有实例化。例如,使用GNU工具链可以执行此操作:

make
nm foo | c++filt | grep 'C<[^>]\+>::f'

其中foo是输出二进制文件的名称。

显然需要更改正则表达式以查找您要查找的模板实例,但此示例适用于您的示例class C

您甚至可以使用非常广泛的正则表达式来查找所有模板实例,无论如何:

grep '<[^>]\+>::'

顺便提一下,这是一个很好的方式来说明如何使用STL或iostream库甚至看起来很小的程序。模板实例化的数量可能真的令人震惊!

答案 1 :(得分:1)

由于在编译时模板实例化之前发生预处理器阶段,因此您不能让编译器根据模板使用预处理器指令执行的操作发出自定义消息。此外,C ++模板虽然功能非常强大,但在编译时没有任何能够发出自定义消息的能力。

答案 2 :(得分:1)

我会亲自采用Dan's方法。

如果这不是一个选项,那么没有标准的方法,但是在这里扩展其他一些选项,可以让编译器为你生成警告,告诉你价值:

template <int N> class C
{
public:
  C ()
  {
    int d1;
    int d1 = d1;  // Using uninitialized variable - warning
  }
};

C<10> c;

g++-Wuninitialized选项一起使用,上面会生成:

t.cc: In constructor 'C<N>::C() [with int N = 10]':
t.cc:7: warning: 'i' is used uninitialized in this function

您可以将其置于启用调试版本的MACRO中。

答案 3 :(得分:1)

通常,生成警告似乎是一种好方法(警告而不是错误,因此您可以在一次编译运行中记录多个内容)。这是我一直在使用的函数,它允许传入一个值并打印它的类型,或者传递一个类型作为模板参数:

template <typename T>                
inline void debug_type(const T&) __attribute__((deprecated));        

template <typename T>                                          
inline void debug_type(const T&) { }                           

template <typename T>                                        
inline void debug_type() __attribute__((deprecated));        

template <typename T>                                            
inline void debug_type() { } 

你可以像这样使用它:

debug_type(1); // Pass a value, let the compiler deduce its type
debug_type<char>(); // Pass a type explicitly

这会产生如下警告:

foo.cpp:73:17: warning: 'void debug_type(const T&) [with T = int]' is deprecated (declared at /tmp/arduino_build_static/sketch/Num.h:13) [-Wdeprecated-declarations]
     debug_type(1);
                 ^
foo.cpp:74:22: warning: 'void debug_type() [with T = char]' is deprecated (declared at /tmp/arduino_build_static/sketch/Num.h:19) [-Wdeprecated-declarations]
 debug_type<char>();

错误消息的T = int部分显示了类型(当然可以是更复杂的模板类型,这只是一个例子)。

此警告相对于其他地方提出的未使用变量警告的一个特别优势是错误位置是调用debug_type的位置,而不是其实现,因此错误中显示的代码段显示了其类型的表达式正在打印(当您想要一次打印几个不同的打印时,这很方便)。

答案 4 :(得分:0)

如果N == 20?

,是否需要错误?

如果是这样,专业化怎么样?

template <> class C <20> 
{
     int class_C_is_templated_with_20[-1];
}

答案 5 :(得分:0)

以下打印出来:

  

Test.cpp:在'C&lt; 20&gt;'的实例化中:   Test.cpp:14:从这里实例化   Test.cpp:9:错误:没有匹配
  呼叫功能   “assertion_failed(MPL _ ::失败************
  (C&lt; 20&gt; :: CLASS_C_TEMPLATED_WITH_I_EQUAL_TO _ :: ************)(mpl _ :: int_&lt; 20&gt;))'

这会打印出一条半清晰的消息,但也会停止编译。我不确定这是不是你想要的。

#include <boost/mpl/assert.hpp>
#include <boost/mpl/int.hpp>

template<int i_>
class C
{
public:

BOOST_MPL_ASSERT_MSG( false, CLASS_C_TEMPLATED_WITH_I_EQUAL_TO_, (boost::mpl::int_<i_>) );

};

int main() {
C<20>();
}

答案 6 :(得分:0)

可能会生成警告(例如,在f方法中声明未使用的空结构的未使用实例)。但是,只有在实例化该方法时,才会触发该警告(有希望也提及N的值)(如果有的话)。另一方面,它可能会根据宏来有条件地编译。

也许还可以在类声明中放入一些东西,在实例化类本身时调用警告(例如,不改变实例的大小)。但是,在用GCC评估static_assert时,我没有任何运气触发警告。