Template instantiation does not "inherit"
The title is quoted from this SO. He discusses the use of SFINAE to detect the existence of a member function with a given signature, and points out a method failure in the accepted answer when dealing with inherited member functions. Specifically, this explanation is as follows
If you're not already smart about this, then a look at the definition
std::shared_ptr<T>
in the title will shed some light. This implementationstd::shared_ptr<T>
derives from the base class from which it inheritsoperator*() const
. Thus, an instance of a templateSFINAE<U, &U::operator*>
that is a "lookup" operator forU = std::shared_ptr<T>
will not be executed because itstd::shared_ptr<T>
does not have itoperator*()
in its own right, and the template creation does not "inherit".This binding does not affect the famous SFINAE approach, using the "Theofofof () Trick" to only detect if T has some mf member function (see, for example, this answer and comments).
Using the terminology from the answer, what is the difference between using T::mf
as a template argument to instantiate a type vs when the compiler determines it by inferring a template function argument? What does "template instance do not inherit" mean? And finally, why doesn't this affect the simplicity of checking the existence of a member, for example here ?
source to share
Minimized example:
struct A {
void a() const;
};
struct B : A {};
template<typename U, void (U::*)() const> struct SFINAE {};
template<typename U> void Test(SFINAE<U, &U::a>*) { }
int main(void)
{
Test<B>(0); // doesn't compile
return 0;
}
Demo .
The problem is that when B::a
inherited from A
, the type &B::a
is actually a "pointer to member A
" - and although it is usually a pointer to a base element can be implicitly converted to pointer-to-member-derived, this conversion does not apply to template arguments without a type, according to §14.3.2 [temp.arg.nontype] / p5:
The following conversions are performed for each expression used as a non-type template-argument. If a template argument of a non-type type cannot be converted to the type of the corresponding template parameter, then the program is poorly formed.
- [...]
- For a non-type template-parameter of a type pointer to a member function, if the template-argument has a type
std::nullptr_t
, the null member pointer conversion (4.11) is applied; otherwise, there is no conversion. If the template argument is a set of overloaded member functions, the member function from the set (13.4) is selected.
source to share