Как напечатать интегральный аргумент шаблона во время компиляции в C ++ - PullRequest
4 голосов
/ 01 декабря 2009

Скажем, я реализовал шаблон класса следующим образом:

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 еще.

Есть ли способ или нет?

Спасибо.

Ответы [ 7 ]

4 голосов
/ 01 декабря 2009

Вы можете добавить шаг после сборки, который находит все экземпляры в выходном двоичном файле после завершения всех компиляций шаблона (ов). Например, используя набор инструментов GNU, вы можете сделать это:

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

Где foo - имя выходного двоичного файла.

Регулярное выражение, очевидно, необходимо изменить, чтобы найти искомые экземпляры шаблона, но этот пример работает для вашего примера class C.

Вы можете даже использовать очень широкое регулярное выражение, чтобы найти все шаблонные экземпляры любого вида:

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

Это, кстати, отличный способ показать, как использование библиотек STL или iostream раздувает даже кажущиеся крошечными программы. Количество шаблонных экземпляров может быть поразительным!

1 голос
/ 10 февраля 2017

В общем, генерация предупреждения кажется хорошим подходом (предупреждение вместо ошибки, поэтому вы можете записать несколько вещей за один прогон компиляции). Вот функция, которую я использовал, которая позволяет передавать значение и печатать его тип или передавать тип в качестве параметра шаблона:

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, а не его реализация, поэтому фрагмент кода, показанный в ошибке, показывает выражение, тип которого напечатано (что может быть удобно, если вы хотите напечатать несколько разных одновременно).

1 голос
/ 01 декабря 2009

Я бы пошел с подходом Дэна лично.

Если это не вариант, тогда нет стандартного подхода, но, расширяя некоторые другие параметры здесь, можно заставить компилятор генерировать для вас предупреждения, которые покажут вам значение:

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, включенный для отладочных сборок.

1 голос
/ 01 декабря 2009

Поскольку фаза препроцессора происходит до создания экземпляра шаблона при компиляции, вы не можете заставить компилятор выдавать пользовательское сообщение, основанное на том, что шаблон делает с использованием директив препроцессора. Более того, шаблоны C ++, хотя и являются чрезвычайно мощными, не способны генерировать пользовательские сообщения во время компиляции.

0 голосов
/ 01 декабря 2009

Может быть возможно сгенерировать предупреждение (например, объявить неиспользуемый экземпляр бесполезной пустой структуры в методе f). Тем не менее, это предупреждение, которое, будем надеяться, также будет содержать упоминание значения N, будет срабатывать (если вообще будет) только при создании экземпляра метода. С другой стороны, он может быть условно скомпилирован в зависимости от макроса.

Возможно, будет также возможно поместить что-то в объявление класса, которое вызывает предупреждение, когда создается экземпляр самого класса (например, без изменения размера экземпляра). Однако мне не повезло с предупреждением при оценке static_assert с GCC.

0 голосов
/ 01 декабря 2009

распечатывается следующее:

Test.cpp: в экземпляре C <20> ’:
Test.cpp: 14: создается здесь
Test.cpp: 9: ошибка: не соответствует
функция для вызова
«Assertion_failed (MPL _ :: не удалось ************
(C <20> :: CLASS_C_TEMPLATED_WITH_I_EQUAL_TO _ :: ************) (mpl _ :: int_ <20>))

Это распечатывает разборчивое сообщение, но также останавливает компиляцию. Я не уверен, что это то, что вы ищете.

#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>();
}
0 голосов
/ 01 декабря 2009

Хотите ошибку, если N == 20?

Если так, то как насчет специализации?

template <> class C <20> 
{
     int class_C_is_templated_with_20[-1];
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...