What is the best and most correct way to define a template function whose argument's type is required to be a subclass of a certain base class?
Here is what I have:
class A {};
class B : public A {};
class C {};
template <typename T>
int foo(T& x) // NB: need a solution that allows a return value
{
A& dummy = x; // require T to be a subclass of A, else SFINAE
return 1;
}
//int foo(C&) { return 2; }
int main()
{
B b;
C c;
std::cout << foo(b) << "\n";
std::cout << foo(c) << "\n"; // should fail unless foo(C&) is defined
}
Is the above correct? I don't like it because it doesn't express intent. I would prefer something that read more like the following bogus code:
template <class A T>
void foo(T& x) {}
Maybe enable_if
can be used somehow?
(Background: In my production code the functions are operators. I need them to be templates for metaprogramming reasons (to deduce the compile time type of T). But I want to restrict them to only match subclasses of A.)
Update #1: In a related question on Template Constraints C++ The following is given:
static_assert(std::is_base_of<A, T>::value, "T must be a sublass of A");
This captures the intent better than A& dummy = x;
however it suffers from the same problem that if void foo(C&) { }
is commented out, foo<T>
still gets specialized for the call to foo(c)
and then the static_assert
fails. Whereas I would like for the compiler to not even try to specialize foo<T>
for cases where the parameter is not a subclass of A.
Update #2: Based on the accepted answer here: Why does enable_if_t in template arguments complains about redefinitions? the following code appears to be close, however it is C++14 specific. I would like a solution portable to current standards.
template <typename T, std::enable_if_t<std::is_base_of<A, T>::value>* = nullptr>
void foo(T& x)
{
}
The advantage of the above is that when void foo(C&)
is defined, the compiler gives the correct error: "error: no matching function for call to 'foo(C&)'".