Static_assert зависит от шаблона класса

Рассмотрим следующий код:

template <unsigned int N>
struct myclass
{
    unsigned int f() {return N;}
    unsigned int g() {static_assert(N > 0, ""); return N-1;}
};

Вопрос: У меня есть гарантия, что следующий код будет скомпилирован:

myclass<0> c;
c.f();

Но следующее не будет:

myclass<0> c;
c.f();
c.g();

Ответ 1

Да, у вас есть эта гарантия. Из [temp.inst]/11, акцент мой:

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

Если вы не вызываете g(), это не требует создания экземпляра, поэтому не должно быть проблем с вызовом myclass<0>{}.f().

Это та же самая гарантия, которая позволяет использовать std::vector и std::map с типами, которые не являются конструктивными по умолчанию, если вы не выполняете такие функции, как call resize() и operator[], соответственно.

Далее, поскольку Jarod42 указывает, заключается в том, что явно создавая экземпляр myclass<0> будет выдавать утверждение, потому что из [temp.explicit]/8:

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

Исключения здесь не применяются.

Ответ 2

Используйте специализированную специализацию:

template <unsigned N>
struct myclass
{
    unsigned f () { return N; }
    unsigned g () { return N-1; }
};

template <>
struct myclass <0>
{
    unsigned f () { return 0; }
};

Ответ 3

Если вы хотите отключить функцию во время компиляции, вы должны использовать enable_if вместо static_assert

template<unsigned int N>
struct Foo {
    unsigned int f() {}
    enable_if_t<(N > 0), unsigned int> g() {}
};

Foo<0> t{};
t.f(); /// this is okay and will compile
// t.g() if I uncomment this line, it will not compile anymore.