I have the following scheme:
struct Baz {};
struct Qux {};
struct Base {
virtual ~Base() {}
virtual void foo() = 0;
};
template<typename T> struct Identity { static bool const value = false; };
template<typename T> void bar(T) { static_assert(Identity<T>::value, "Busted!!!"); }
template<> void bar<Baz>(Baz) {}
template<typename T>
struct Derived : Base {
T m;
void foo() { bar(m); }
};
int main() {
Base *b0 = new Derived<Baz>;
b0->foo();
Base *b1 = new Derived<Qux>;
(void) b1;
}
That is, I have a pure virtual class Base
and a template class Derived
that inherits from Base
and overrides the pure virtual function foo
as required. Now, inside foo
I call function template bar
. bar
has a specialization for class Baz
but not for class Qux
. When in main
I'm trying to materialize an object of Derived<Baz>
everything's OK. But when I try to materialize an object of Derived<Qux>
compiler hits static_assert
.
Is there a way to transform my code in such a way that compiler will hit static assert in Derived<Qux>
only if Derived<Qux>::foo()
is called.
That is, materializing an object of Derived<Qux>
will pass:
Base *b1 = new Derived<Qux>;
But when later in code the programmer tries to call:
b1->foo(); // compile error static assert
The standard says an interesting thing at [temp.inst]/9:
An implementation shall not implicitly instantiate a function template, a variable template, a member template, a non-virtual member function, a member class, a static data member of a class template, or a substatement of a constexpr if statement, unless such instantiation is required. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated.
The decision of instantiating a virtual function is up to the implementation, but only if it is not needed otherwise. The question we are faced with is therefore: when is the definition needed according to the standard itself?
The answer is at [class.virtual]/11 and [temp.inst]/2:
A virtual function declared in a class shall be defined, or declared pure in that class, or both; no diagnostic is required
The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions, default arguments, or noexcept-specifiers of the class member functions
So any instantiation of the class template, will instantiate a declaration of Derived::foo
, which by a chain reaction requires a definition. So the definition must be instantiated too, if it is available.
The only way an implementation can exercise the leeway it is given in the first quoted paragraph, is if Derived::foo
is pure virtual too. As an example, both Clang and GCC do just that. That of course is likely to be of limited help to you.
So to make a long story short, it's a no-starter, so long as the function is virtual (and not pure virtual).