Так работает CRTP из-за двухэтапного анализа шаблона. Функции-члены шаблона не анализируются до момента их создания.
РЕДАКТИРОВАТЬ: Может быть, формулировка не очень точная. Что я хотел сказать, когда компилятор видит
class B : public A< B > {...};
, он проходит через A< B >
, замечает, что есть функция B get() {...}
, но не оценивает ее определение, оставляя его до фактического создания экземпляра функции, когда B
должен быть завершенным типом.
РЕДАКТИРОВАТЬ: Я верю, точные правила описаны в разделе 14.6 Стандарт (как Алс указал в своем ответе). Он имеет дело с именами dependent
и non-dependent
и их разрешением в разное время во время компиляции в соответствии с двухфазным поиском имени шаблона. Однако, к сожалению, реализация двухфазного поиска имени может отличаться от Standard на разных компиляторах. Один и тот же код может компилироваться в GCC, а может не в MSVC ++ и наоборот. Более того, один и тот же код может быть отклонен одним и тем же компилятором. На MSVC ++ у меня была проблема, когда базовый класс использовал указатель на функцию производного класса в качестве аргумента по умолчанию для своей функции. Он не компилировался в MSVC ++ и компилировался в GCC (правильно). Однако использование конструктора производного класса в качестве параметра по умолчанию скомпилировано с обоими компиляторами, даже в MSVC ++. Пойди разберись.