2016-10-31 3 views
0

У меня есть некоторый шаблонный код для абстракции таймеров на моем устройстве avr. Наиболее важная часть здесь:static_assert всегда вычисляет true (avr, g ++)

template <typename T> 
class Timerx8bit 
{ 
    T reg; 

    static_assert(T::res == TimerResolution::bit8, "The timer template is 8bit, registers must also be 8bit"); 
} 


struct Timer0 
{ 
    constexpr static const TimerResolution res = TimerResolution::bit16; 

    volatile uint8_t* tccra = &TCCR0A; 
    volatile uint8_t* tccrb = &TCCR0B; 
    //[...] 
}; 

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

Проблема, кажется, в шаблоне, если я поставил «TimerResolution :: bit8! = TimerResolution :: bit8» в качестве условия, компиляция завершилась неудачно, как ожидалось, но «T :: res! = T :: res» компилируется без каких-либо проблем ... что мне здесь не хватает?

EDIT: При подготовке полного примера кода, я нашел эту проблему, хотя я до сих пор не совсем понимаю, почему он ведет себя таким образом. Во-первых, код:

enum class TimerResolution_test 
{ 
    bit8, 
    bit16 
}; 

struct Timer0_test 
{ 
    constexpr static const TimerResolution_test res = TimerResolution_test::bit8; 
}; 

template <typename T> 
class Timerx8bit_test 
{ 
public: 
    constexpr static const TimerResolution_test res = TimerResolution_test::bit8; 

private: 
    T reg; 

    static_assert(T::res != T::res, "The timer template is 8bit, registers must also be 8bit"); 
}; 

template<typename Timer> 
class pwm_test 
{ 

}; 

Инстанцирование:

pwm_test<Timerx8bit_test<Timer0_test>> testTimer; // Compiles 
Timerx8bit_test<Timer0_test> testTimer2; // Fails 

Второй конкретизации терпит неудачу с static_assert, как описано выше. Если я ставлю «ложь» вместо шаблонного условия, это не сработает в обоих случаях ... почему? Не должно ли это быть в обоих случаях с исходным шаблоном?

+3

Что такое 'TimerResolution'? Что такое 'TimerResolution :: bit8'? Если возможно, попробуйте создать [Минимальный, полный и проверенный пример] (http://stackoverflow.com/help/mcve) и покажите нам. –

+1

Невозможно воспроизвести. Я помещаю ваш код в один файл cpp, и когда он скомпилирован, static_assert не работает. –

+0

Три компилятора согласны, поэтому, вероятно, это не ошибка компилятора. Билут Мне трудно представить, что еще может быть. –

ответ

1

Шаблоны не требуют полного определения типа сразу (подумайте о CRTP). Они должны использовать тип таким образом, который потребует полного определения типа. Ваш pwm_test не использует параметр типа, который он указан, кроме как по имени. Поэтому тело шаблона никогда не нужно создавать.

Во втором случае вы создаете объект, поэтому, естественно, создается экземпляр объекта шаблона.

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

template<typename Timer> 
class pwm_test 
{ 
    enum { _ = sizeof(Timer) }; 
}; 

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


Чтобы ответить на другой вопрос, почему static_assert результата в немедленной ошибке в одном случае, но не другой:

§14.6/8[temp.res]

Зная, какие имена имена типов позволяют проверять синтаксис каждого шаблона . Программа плохо сформирована, не требуется диагностика, если:

  • ...
  • гипотетический экземпляр шаблона сразу же после его определения будет плохо сформирован из-за конструкции, которая не зависит от параметра шаблона, или

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

Когда static_assert(T::res != T::res) встречается, компилятор проверяет синтаксис, но он не может сделать вывод, что T::res != T::res всегда ложно, что информация доступна только тогда, когда T известно (в конце концов, T::res может быть что-то, что перегружает operator!= всегда возвращает истину) ,

+0

Спасибо за предложение. В готовом коде класс pwm будет иметь член таймера, так что больше нет проблем - мне просто хотелось бы понять, почему он не создан для проверки состояния компиляции ... –

+0

@KrzysztofBorowczyk, делает помогите? – StoryTeller

+0

@StorryTeller, да, но только частично. Утверждение находится в классе, поэтому вызов участника не требуется. Я понимаю, что тело шаблона не нужно создавать, но если это не так, то почему ложь в static_assert терпит неудачу? Если он не создан, не следует ли его оставить без обработки? –