tags:

views:

280

answers:

6

Say I have implemented a template class like this:

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

I wish that while the compiler compiles a clause like

C<20> c;

it would print out a message

"class C is templated with N = 20"

I've tried with #pragma and static_assert in vain.

The problem is that

  1. with #pragma and static_assert, I could not embed an integral(20 here) into a message;
  2. with preprocessors, it's too early that N is not substituted with 20 yet.

Is there any way or no way?

Thanks.

+1  A: 

Since the pre-processor phase occurs before template instantiation when you compile, you can't have the compiler emit a custom message based on something that a template does using pre-processor directives. Moreover, C++ templates, while extremely powerful, don't have any capacity to emit custom messages at compile time.

Charles Salvia
I doubt that. With some fantasy you could rework one or another warning to a specific template diagnostic.
drhirsch
static_assert can emit message. it's a c++0x feature and available in VC++10. However, it's not possible to pass in an integral to be outpput.
t.g.
BOOST_MPL_ASSERT_MSG can output a message-like error in c++ (not 0x)
KitsuneYMG
@t.g. `static_assert` would stop compilation at will. It would possibly not continue compilation to see other instantiations happen.
Johannes Schaub - litb
@litb Thanks, I did not realize that before.
t.g.
A: 

Do you want an error, if N == 20?

If so, how about specialization?

template <> class C <20> 
{
     int class_C_is_templated_with_20[-1];
}
drhirsch
no, I do not want ant predicates which is easy with static_assert. I want the actual value.
t.g.
A: 

The following prints out:

Test.cpp: In instantiation of ‘C<20>’:
Test.cpp:14: instantiated from here
Test.cpp:9: error: no matching
function for call to
‘assertion_failed(mpl_::failed************
(C<20>::CLASS_C_TEMPLATED_WITH_I_EQUAL_TO_::************)(mpl_::int_<20>))’

This prints out a semi-legible message, but also halts compilation. I'm not sure if this is what you are looking for.

#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>();
}
KitsuneYMG
Thanks, but I meant to output a useful message rather than halt the compiling. C<20> ought to be legal in my case.
t.g.
+2  A: 

You could add a post-build step that finds all instantiations within the output binary after all compilations of the template(s) are complete. For instance, using the GNU toolchain you could do this:

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

Where foo is the name of the output binary.

The regular expression obviously needs to be altered to find the template instantiations you are looking for, but this example works for your example class C.

You could even use a very broad regex to find all template instantiations, of any kind:

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

This is incidentally a great way to illustrate how use of the STL or iostream libraries bloats even seemingly tiny programs. The number of template instantiations can be truly astounding!

Dan Moulding
Thanks for the idea. I tried with grep on a VC++10-generated binary but could not find anything. Seems it only works for g++.
t.g.
A: 

It might be possible to generate a warning (e.g declare an unused instance of a useless empty struct in the f method). However, that warning, which will hopefully also mention the value of N will be triggered (if at all) only when you instantiate the method. On the other hand, it might be conditionally compiled depending on a macro.

Perhaps it will also be possible to put something in the class declaration that invokes the warning when the class itself is instantiated (without, for example, changing the size of the instance). I haven't had any luck triggering a warning while evaluating a static_assert with GCC, though.

UncleBens
A: 

I'd go with Dan's approach personally.

If that's not an option, then there's no standard approach, but extending on some of the other options here, it is possible to make the compiler generating warnings for you that will show you the value:

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

C<10> c;

Using g++ with the -Wuninitialized option, the above generates:

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

You could put this into a MACRO enabled for debug builds.

Richard Corden