Подтвердить что ты не робот

Отладка шаблонов

При выполнении метапрограммирования с использованием шаблонов С++ существует ли метод, который можно использовать, вроде отладчика, для того, чтобы просмотреть, как создаются и выполняются шаблоны? Кажется, сейчас, создавая сложную сеть шаблонов, на самом деле не очень хороший способ отладки их, кроме поиска сообщений об ошибках complier, чтобы увидеть, как создаются шаблоны (если есть какие-либо ошибки компилятора) и попытка отступить от сообщений об ошибках, если создается что-то неожиданное. Я не совсем уверен, что то, что я ищу, даже существует, так как это должно было быть чем-то, что было сделано во время компиляции, но в основном это был бы метод, вроде как переход кода и рассмотрение фрейма стека в gdb во время выполнения, где компилятор может быть остановлен и среда проверена для последовательности, в которой создается экземпляр шаблона или набора вложенных шаблонов.

Например, скажем, я создал простой код, например:

template<typename T, typename R = void>
struct int_return_type {};

template<typename R>
struct int_return_type<int, R>
{
    typedef R type;
};

template<typename T, typename R = void>
struct float_return_type {};

template<typename R>
struct float_return_type<float, R> 
{
    typedef R type;
};

template<typename T>
typename int_return_type<T>::type test()
{
    cout << "T type is int" << endl;
}

template<typename T>
typename float_return_type<T>::type test()
{
    cout << "T type is float" << endl;
}

int main()
{
    test<int>();
    test<float>();
    return 0;
}

Я знаю, что это относительно простой код для последующего использования, но шаблоны могут стать немного более активными, особенно при выполнении метапрограммирования, рекурсии и т.д. Я понимаю, что complier выдаст сообщения об ошибках, которые можно использовать для вывода того, как шаблоны но я также задаюсь вопросом, что можно сделать, когда фактический шаблон кода верен в синтаксическом смысле, но результаты выполнения все еще неверны. Было бы неплохо, например, иметь способ остановить компилятор и посмотреть, что было создано test, а также int_return_type и float_return_type, или какие экземпляры не выполнялись.

Доступны ли только доступные параметры для отладки шаблонов с этим уровнем детализации 1) сообщения об ошибках компилятора при неправильном коде и 2) комбинация дизассемблеров и отладчиков, чтобы увидеть, какой экземпляр был сгенерирован, неверные результаты времени? Или есть некоторые другие утилиты, которые помогают "наблюдать" за тем, как создаются шаблоны, и посмотреть/проверить, какой код генерируется компилятором для исследования и отладки ошибок шаблона?

4b9b3361

Ответ 1

Это довольно простые, но в большинстве случаев они работали на меня. Мне интересно посмотреть, что другие тоже говорят.

Извините за надуманные примеры.

Использовать песочницы

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

Укажите временные типы

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

template<typename T>
  T calc(const T &val) {
    return some_other_calc(val) / 100.0;
  }

Рассказывая компилятору, какой тип, который вы ожидаете, сработает быстрее и потенциально даст вам лучшее сообщение для решения.

template<typename T>
  T calc(const T &val) {
    T val_ = some_other_calc(val);
    return val_ / 100.0;
  }

Использовать typeid

Использование typeid(T).name() для печати имен шаблонов в операциях отладки. Это даст вам строку, которую вы можете использовать, чтобы увидеть, как компилятор решил выполнить тип.

template<typename T>
  typename void test() {
    std::cout << "testing type " << typeid(T).name() << std::endl;
    // ...
  }

Избегайте ненужных реализаций по умолчанию

Напишите шаблоны таким образом, чтобы они не имели реализации по умолчанию.

template<typename T, bool is_integral = boost::is_numeric<T>::value >
  struct my_traits;

template<typename T>
  struct my_traits<T, true> {
    typedef uint32_t cast_type;
  };

template<typename T>
  void print_whole_number(T &val) {
    std::cout << static_cast<my_traits<T>::cast_type>(val) << std::endl;
  }

Это позволяет пользователям print_whole_number иметь собственную специализацию my_traits. Они получат ошибку компилятора вместо половины работы, потому что вы не можете обеспечить хорошую реализацию для всех типов. Ошибка компилятора не будет сразу же полезной, если будет использоваться в разрозненной части базы кода, по общему признанию.

Ответ 2

Да, есть отладчик метапрограммирования шаблона. Templight

Ответ 3

Мне нравится использовать превосходный веб-компилятор Comeau для отладки. Он может заметить ошибки в стандартном компиляторе, где другие компиляторы не могут...

Компания "Комо" имеет большое преимущество в предоставлении гораздо более читаемых сообщений об ошибках, чем GCC или MSVC.

Кроме того, не забудьте использовать static_assert везде, где это возможно, даже если вы уверены, что ответ верен.