#include <iostream>
template<class D>
struct Base {
template<class T>
void foo(T val) {
static_assert(false, "Error! User has not defined the 'foo(...)'");
std::cout << "Base::foo\n";
}
void call_foo(int val) {
static_cast<D*>(this)->foo(val);
}
};
struct Derived : public Base<Derived> {
template<class T>
void foo(T val) { std::cout << "Derived::foo\n"; }
};
struct DerivedFail : public Base<DerivedFail> {
template<class T>
void foo(T val) { std::cout << "DerivedFail::foo\n"; }
};
int main() {
Derived().call_foo(1);
DerivedFail().call_foo(1);
return 0;
}
Если закомментировать DerivedFail::foo срабатывал static_assert.
После одного из последних обновлений MSVC (не знаю точно после какого) static_assert срабатывает всегда.
GCC ведет себя также https://gcc.godbolt.org/z/3vz436sn9
Как вылечить?
Re: Как проверить, определил ли пользователь метод?
Я не уверен на 100%, но насколько я понимаю, в этом случае старые MS компиляторы проверяли только корректнось синтаксиса. Если метод не инстанцируется, то там вообще можно писать любой мусор, лишь бы он был корректен с точки зрения абстрактного С++. Ах сколько у меня кода перестало работать шаблонного, из-за того, что иногда не умышленно дергаешь реализацию, которая не объявлена в точке использования .
σ>Завтра обновится, и такой сорт IFNDR тоже перестанет компилироваться.
Не, теперь всё по стандарту.
Re[4]: Как проверить, определил ли пользователь метод?
σ>>А что нарушалось?
V>Я не уверен на 100%, но насколько я понимаю, в этом случае старые MS компиляторы проверяли только корректнось синтаксиса. Если метод не инстанцируется, то там вообще можно писать любой мусор, лишь бы он был корректен с точки зрения абстрактного С++.
Не уверен на 100%, но насколько я понимаю, можно даже корректность синтаксиса у шаблона не проверять (см. g в https://timsong-cpp.github.io/cppwp/n4861/temp.res#8.example-1)
Возможно, пример некорректный и грамматика template-declaration → template-headdeclaration намекает, что declaration должен быть синтаксически корректен даже без инстанциаций? А может и нет.
σ>>Завтра обновится, и такой сорт IFNDR тоже перестанет компилироваться.
V>Не, теперь всё по стандарту.
Ничего страшного, обязательные [[no_unique_address]] и еmpty base optimization уже существуют в языке, скоро при движении в эту сторону и полноценные типы нулевого размера появятся. Так что этот пункт будет не применим.
Но, конечно, способу Videoman'a
это не сильно поможет: сейчас он неправилен лишь формально и если придираться, а после станет просто неправильным
А если серьёзно, то у sizeof(T)==0 есть и другие недостатки: например, с void не работает, и с неполными типами тоже. Не советую так писать.