static_assert always computes true (avr, g++) - c++

I have some templated code for timers abstraction on my avr device. Most relevant part here is:
template <typename T>
class Timerx8bit
{
T reg;
static_assert(T::res == TimerResolution::bit8, "The timer template is 8bit, registers must also be 8bit");
}
struct Timer0
{
constexpr static const TimerResolution res = TimerResolution::bit16;
volatile uint8_t* tccra = &TCCR0A;
volatile uint8_t* tccrb = &TCCR0B;
//[...]
};
Now I feed the Timer0 to the template. The problem with that code is, that the static assert seems to evaluate always to true, although in the above situation it should fail. TimerResolution is just an enum class.
The problem seems to be in the template, if I put "TimerResolution::bit8 != TimerResolution::bit8" as the condition, compilation fails as expected, but "T::res != T::res" compiles without any problems... what am I missing here?
EDIT:
While preparing full example of code I found the problem, although I still don't quite understand why it behaves that way. First, the code:
enum class TimerResolution_test
{
bit8,
bit16
};
struct Timer0_test
{
constexpr static const TimerResolution_test res = TimerResolution_test::bit8;
};
template <typename T>
class Timerx8bit_test
{
public:
constexpr static const TimerResolution_test res = TimerResolution_test::bit8;
private:
T reg;
static_assert(T::res != T::res, "The timer template is 8bit, registers must also be 8bit");
};
template<typename Timer>
class pwm_test
{
};
Instantiation:
pwm_test<Timerx8bit_test<Timer0_test>> testTimer; // Compiles
Timerx8bit_test<Timer0_test> testTimer2; // Fails
The second instantiation fails with the static_assert as above. If I put 'false' instead of the templated condition it fails in both cases... why is that? Shouldn't it fail in both cases with the original templated condition?

Templates don't require the complete type definition immediately (think CRTP). They must use the type in a way that will cause the complete type definition to be required. Your pwm_test doesn't use the type parameter it is given except by name. So the template body never needs to be instantiated.
In the second case you create an object, so naturally the template body instantiation happens.
So you need to force the instantiation by providing a context where it must happen:
template<typename Timer>
class pwm_test
{
enum { _ = sizeof(Timer) };
};
On a related note, if you have any static assertions in a member function of a template, those won't be triggered until you add a call to the function in your code.
To answer your other question, why does static_assert result in an immediate error in one case but not the other:
§14.6/8 [temp.res]
Knowing which names are type names allows the syntax of every template
to be checked. The program is ill-formed, no diagnostic required, if:
...
a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not
depend on a template parameter, or
So when encountering static_assert(false) while parsing the template, the compiler can deduce that all templates instantiations will be ill-formed. In this case it chooses to issue a diagnostic immediately (note that it doesn't have to).
When static_assert(T::res != T::res) is encountered, the compiler checks the syntax, but it cannot deduce that T::res != T::res is always false, that information is only available when T is known (after all, T::res can be something that overloads operator!= to always return true).

Related

While trying to use SFINAE to disable functions, have I created undefined behavior?

I am trying to use SFINAE to disable certain functions of a class based on some non-templated enum arguments.
The following code does NOT compile with gcc, but appears to compile and work as expected when using the msvc compiler.
#include <iostream>
#include <type_traits>
enum class B { VARIANT1, VARIANT2 };
template<B B_VAL>
struct A {
template<class = std::enable_if_t<B_VAL == B::VARIANT1>>
void func1() {
std::cout<<"VARIANT1"<<std::endl;
}
template<class = std::enable_if_t<B_VAL == B::VARIANT2>>
void func2() {
std::cout<<"VARIANT2"<<std::endl;
}
};
int main()
{
A<B::VARIANT1> a;
a.func1();
}
The expected (and msvcs) behavior is that calling a function whose enable_if_t condition equates to false results in a compile time error, or the removal of the function candidate for overload resolution if an overloaded function was present in the example. In all other cases, the code should compile normally.
gcc on the other hand tells me that it can't find a type named "type" in "struct std::enable_if<false, void>" for the enable_if_t in the template of func2, which makes perfect sense as the member named "type" is only present in enable_if if the condition equates to true. But shouldn't this be the desired behavior for the SFINAE functionality and shouldn't the compiler ignore func2, as it is never called?
I now have three questions:
As the two compilers produce different behavior, is it undefined and if yes, which parts/statements?
Is SFINAE suited to achieve my goal, or have I misunderstood its use case?
Would I be better off by using static asserts as alternative?
I am sorry if this question is a duplicate of this one, but I don't think that the answers there provided much help with my problem.
GCC is right. And it's because you aren't using SFINAE for your function. It may appear that you do because you employ utilities for SFINAE from the standard library, but there is a crucial ingredient missing here.
The 'S' in "SFINAE" stands for substitution. The substitution of template arguments into the parameters of a template we are trying to instantiate. Now, the template in question is func2. And for SFINAE to work, it is func2's argument that must fail to be substituted for its parameters. But here
std::enable_if_t<B_VAL == B::VARIANT2>
There is no parameter of func2 in use. It doesn't depend on anything that happens during substitution into func2. It's just an invalid type, completely independent of an attempt to actually instantiate func2.
It's not hard to fix though
template<B B_VAL_ = B_VAL, class = std::enable_if_t<B_VAL_ == B::VARIANT1>>
void func1() {
std::cout<<"VARIANT1"<<std::endl;
}
template<B B_VAL_ = B_VAL, class = std::enable_if_t<B_VAL_ == B::VARIANT2>>
void func2() {
std::cout<<"VARIANT2"<<std::endl;
}
Now, the check is against the substitution into the correct template.

How does this implementation of std::is_class work?

I'm trying to understand the implementation of std::is_class. I've copied some possible implementations and compiled them, hoping to figure out how they work. That done, I find that all the computations are done during compilation (as I should have figured out sooner, looking back), so gdb can give me no more detail on what exactly is going on.
The implementation I'm struggling to understand is this one:
template<class T, T v>
struct integral_constant{
static constexpr T value = v;
typedef T value_type;
typedef integral_constant type;
constexpr operator value_type() const noexcept {
return value;
}
};
namespace detail {
template <class T> char test(int T::*); //this line
struct two{
char c[2];
};
template <class T> two test(...); //this line
}
//Not concerned about the is_union<T> implementation right now
template <class T>
struct is_class : std::integral_constant<bool, sizeof(detail::test<T>(0))==1
&& !std::is_union<T>::value> {};
I'm having trouble with the two commented lines. This first line:
template<class T> char test(int T::*);
What does the T::* mean? Also, is this not a function declaration? It looks like one, yet this compiles without defining a function body.
The second line I want to understand is:
template<class T> two test(...);
Once again, is this not a function declaration with no body ever defined? Also what does the ellipsis mean in this context? I thought an ellipsis as a function argument required one defined argument before the ...?
I would like to understand what this code is doing. I know I can just use the already implemented functions from the standard library, but I want to understand how they work.
References:
std::is_class
std::integral_constant
What you are looking at is some programming technologie called "SFINAE" which stands for "Substitution failure is not an error". The basic idea is this:
namespace detail {
template <class T> char test(int T::*); //this line
struct two{
char c[2];
};
template <class T> two test(...); //this line
}
This namespace provides 2 overloads for test(). Both are templates, resolved at compile time. The first one takes a int T::* as argument. It is called a Member-Pointer and is a pointer to an int, but to an int thats a member of the class T. This is only a valid expression, if T is a class.
The second one is taking any number of arguments, which is valid in any case.
So how is it used?
sizeof(detail::test<T>(0))==1
Ok, we pass the function a 0 - this can be a pointer and especially a member-pointer - no information gained which overload to use from this.
So if T is a class, then we could use both the T::* and the ... overload here - and since the T::* overload is the more specific one here, it is used.
But if T is not a class, then we cant have something like T::* and the overload is ill-formed. But its a failure that happened during template-parameter substitution. And since "substitution failures are not an error" the compiler will silently ignore this overload.
Afterwards is the sizeof() applied. Noticed the different return types? So depending on T the compiler chooses the right overload and therefore the right return type, resulting in a size of either sizeof(char) or sizeof(char[2]).
And finally, since we only use the size of this function and never actually call it, we dont need an implementation.
Part of what is confusing you, which isn't explained by the other answers so far, is that the test functions are never actually called. The fact they have no definitions doesn't matter if you don't call them. As you realised, the whole thing happens at compile time, without running any code.
The expression sizeof(detail::test<T>(0)) uses the sizeof operator on a function call expression. The operand of sizeof is an unevaluated context, which means that the compiler doesn't actually execute that code (i.e. evaluate it to determine the result). It isn't necessary to call that function in order to know the sizeof what the result would be if you called it. To know the size of the result the compiler only needs to see the declarations of the various test functions (to know their return types) and then to perform overload resolution to see which one would be called, and so to find what the sizeof the result would be.
The rest of the puzzle is that the unevaluated function call detail::test<T>(0) determines whether T can be used to form a pointer-to-member type int T::*, which is only possible if T is a class type (because non-classes can't have members, and so can't have pointers to their members). If T is a class then the first test overload can be called, otherwise the second overload gets called. The second overload uses a printf-style ... parameter list, meaning it accepts anything, but is also considered a worse match than any other viable function (otherwise functions using ... would be too "greedy" and get called all the time, even if there's a more specific function t hat matches the arguments exactly). In this code the ... function is a fallback for "if nothing else matches, call this function", so if T isn't a class type the fallback is used.
It doesn't matter if the class type really has a member variable of type int, it is valid to form the type int T::* anyway for any class (you just couldn't make that pointer-to-member refer to any member if the type doesn't have an int member).
The std::is_class type trait is expressed through a compiler intrinsic (called __is_class on most popular compilers), and it cannot be implemented in "normal" C++.
Those manual C++ implementations of std::is_class can be used in educational purposes, but not in a real production code. Otherwise bad things might happen with forward-declared types (for which std::is_class should work correctly as well).
Here's an example that can be reproduced on any msvc x64 compiler.
Suppose I have written my own implementation of is_class:
namespace detail
{
template<typename T>
constexpr char test_my_bad_is_class_call(int T::*) { return {}; }
struct two { char _[2]; };
template<typename T>
constexpr two test_my_bad_is_class_call(...) { return {}; }
}
template<typename T>
struct my_bad_is_class
: std::bool_constant<sizeof(detail::test_my_bad_is_class_call<T>(nullptr)) == 1>
{
};
Let's try it:
class Test
{
};
static_assert(my_bad_is_class<Test>::value == true);
static_assert(my_bad_is_class<const Test>::value == true);
static_assert(my_bad_is_class<Test&>::value == false);
static_assert(my_bad_is_class<Test*>::value == false);
static_assert(my_bad_is_class<int>::value == false);
static_assert(my_bad_is_class<void>::value == false);
As long as the type T is fully defined by the moment my_bad_is_class is applied to it for the first time, everything will be okay. And the size of its member function pointer will remain what it should be:
// 8 is the default for such simple classes on msvc x64
static_assert(sizeof(void(Test::*)()) == 8);
However, things become quite "interesting" if we use our custom type trait with a forward-declared (and not yet defined) type:
class ProblemTest;
The following line implicitly requests the type int ProblemTest::* for a forward-declared class, definition of which cannot be seen by the compiler right now.
static_assert(my_bad_is_class<ProblemTest>::value == true);
This compiles, but, unexpectedly, breaks the size of a member function pointer.
It seems like the compiler attempts to "instantiate" (similarly to how templates are instantiated) the size of a pointer to ProblemTest's member function in the same moment that we request the type int ProblemTest::* within our my_bad_is_class implementation. And, currently, the compiler cannot know what it should be, thus it has no choice but to assume the largest possible size.
class ProblemTest // definition
{
};
// 24 BYTES INSTEAD OF 8, CARL!
static_assert(sizeof(void(ProblemTest::*)()) == 24);
The size of a member function pointer was trippled! And it cannot be shrunk back even after the definition of class ProblemTest has been seen by the compiler.
If you work with some third party libraries that rely on particular sizes of member function pointers on your compiler (e.g., the famous FastDelegate by Don Clugston), such unexpected size changes caused by some call to a type trait might be a real pain. Primarily because type trait invocations are not supposed to modify anything, yet, in this particular case, they do -- and this is extremely unexpected even for an experienced developer.
On the other hand, had we implemented our is_class using the __is_class intrinsic, everything would have been OK:
template<typename T>
struct my_good_is_class
: std::bool_constant<__is_class(T)>
{
};
class ProblemTest;
static_assert(my_good_is_class<ProblemTest>::value == true);
class ProblemTest
{
};
static_assert(sizeof(void(ProblemTest::*)()) == 8);
Invocation of my_good_is_class<ProblemTest> does not break any sizes in this case.
So, my advice is to rely on the compiler intrinsics when implementing your custom type traits like is_class wherever possible. That is, if you have a good reason to implement such type traits manually at all.
What does the T::* mean? Also, is this not a function declaration? It looks like one, yet this compiles without defining a function body.
The int T::* is a pointer to member object. It can be used as follows:
struct T { int x; }
int main() {
int T::* ptr = &T::x;
T a {123};
a.*ptr = 0;
}
Once again, is this not a function declaration with no body ever defined? Also what does the ellipsis mean in this context?
In the other line:
template<class T> two test(...);
the ellipsis is a C construct to define that a function takes any number of arguments.
I would like to understand what this code is doing.
Basically it's checking if a specific type is a struct or a class by checking if 0 can be interpreted as a member pointer (in which case T is a class type).
Specifically, in this code:
namespace detail {
template <class T> char test(int T::*);
struct two{
char c[2];
};
template <class T> two test(...);
}
you have two overloads:
one that is matched only when a T is a class type (in which case this one is the best match and "wins" over the second one)
on that is matched every time
In the first the sizeof the result yields 1 (the return type of the function is char), the other yields 2 (a struct containing 2 chars).
The boolean value checked is then:
sizeof(detail::test<T>(0)) == 1 && !std::is_union<T>::value
which means: return true only if the integral constant 0 can be interpreted as a pointer to member of type T (in which case it's a class type), but it's not a union (which is also a possible class type).
Test is an overloaded function that either takes a pointer to member in T or anything. C++ requires that the best match be used. So if T is a class type it can have a member in it...then that version is selected and the size of its return is 1. If T is not a class type then T::* make zero sense so that version of the function is filtered out by SFINAE and won't be there. The anything version is used and it's return type size is not 1. Thus checking the size of the return of calling that function results in a decision whether the type might have members...only thing left is making sure it's not a union to decide if it's a class or not.
Here is standard wording:
[expr.sizeof]:
The sizeof operator yields the number of bytes occupied by a non-potentially-overlapping object of the type of its operand.
The operand is either an expression, which is an unevaluated operand
([expr.prop])......
2. [expr.prop]:
In some contexts, unevaluated operands appear ([expr.prim.req], [expr.typeid], [expr.sizeof], [expr.unary.noexcept], [dcl.type.simple], [temp]).
An unevaluated operand is not evaluated.
3. [temp.fct.spec]:
[Note: Type deduction may fail for the following reasons:
...
(11.7) Attempting to create “pointer to member of T” when T is not a class type.
[ Example:
template <class T> int f(int T::*);
int i = f<int>(0);
— end example
]
As above shows, it is well-defined in standard :-)
4. [dcl.meaning]:
[Example:
struct X {
void f(int);
int a;
};
struct Y;
int X::* pmi = &X::a;
void (X::* pmf)(int) = &X::f;
double X::* pmd;
char Y::* pmc;
declares pmi, pmf, pmd and pmc to be a pointer to a member of X of type int, a pointer to a member of X of type void(int), a pointer to a member ofX of type double and a pointer to a member of Y of type char respectively.The declaration of pmd is well-formed even though X has no members of type double. Similarly, the declaration of pmc is well-formed even though Y is an incomplete type.

Compile time template instantiation check

Is it possible to check if a template type has been instantiated at compile time so that I can use this information in an enable_if specialization?
Let's say I have
template <typename T> struct known_type { };
Can I somehow define some is_known_type whose value is true if known_type is instantiated at compile time?
It's possible to do this if you leverage the fact that specific expressions may or may not be used in places where constexprs are expected, and that you can query to see what the state is for each candidate you have. Specifically in our case, the fact that constexprs with no definition cannot pass as constant expressions and noexcept is a guarantee of constant expressions. Hence, noexcept(...) returning true signals the presence of a properly defined constexpr.
Essentially, this treats constexprs as Yes/No switches, and introduces state at compile-time.
Note that this is pretty much a hack, you will need workarounds for specific compilers (see the articles ahead) and this specific friend-based implementation might be considered ill-formed by future revisions of the standard.
With that out of the way...
User Filip Roséen presents this concept in his article dedicated specifically to it.
His example implementation is, with quoted explanations:
constexpr int flag (int);
A constexpr function can be in either one of two states; either it is
usable in a constant-expression, or it isn't - if it lacks a
definition it automatically falls in the latter category - there is no
other state (unless we consider undefined behavior).
Normally, constexpr functions should be treated exactly as what they
are; functions, but we can also think of them as individual handles to
"variables" having a type similar to bool, where each "variable" can
have one of two values; usable or not-usable.
In our program it helps if you consider flag to be just that; a handle
(not a function). The reason is that we will never actually call flag
in an evaluated context, we are only interested in its current state.
template<class Tag>
struct writer {
friend constexpr int flag (Tag) {
return 0;
}
};
writer is a class template which, upon instantiation, will create a
definition for a function in its surrounding namespace (having the
signature int flag (Tag), where Tag is a template-parameter).
If we, once again, think of constexpr functions as handles to some
variable, we can treat an instantiation of writer as an
unconditional write of the value usable to the variable behind the
function in the friend-declaration.
template<bool B, class Tag = int>
struct dependent_writer : writer<Tag> { };
I would not be surprised if you think dependent_writer looks like a
rather pointless indirection; why not directly instantiate writer
where we want to use it, instead of going through dependent_writer?
Instantiation of writer must depend on something to prevent immediate instantiation, and;
dependent_writer is used in a context where a value of type bool can be used as dependency.
template<
bool B = noexcept (flag (0)),
int = sizeof (dependent_writer<B>)
>
constexpr int f () {
return B;
}
The above might look a little weird, but it's really quite simple;
will set B = true if flag(0) is a constant-expression, otherwise B = false, and;
implicitly instantiates dependent_writer (sizeof requires a completely-defined type).
The behavior can be expressed with the following pseudo-code:
IF [ `int flag (int)` has not yet been defined ]:
SET `B` = `false`
INSTANTIATE `dependent_writer<false>`
RETURN `false`
ELSE:
SET `B` = `true`
INSTANTIATE `dependent_writer<true>`
RETURN `true`
Finally, the proof of concept:
int main () {
constexpr int a = f ();
constexpr int b = f ();
static_assert (a != b, "fail");
}
I applied this to your particular problem. The idea is to use the constexpr Yes/No switches to indicate whether a type has been instantiated. So, you'll need a separate switch for every type you have.
template<typename T>
struct inst_check_wrapper
{
friend constexpr int inst_flag(inst_check_wrapper<T>);
};
inst_check_wrapper<T> essentially wraps a switch for whatever type you may give it. It's just a generic version of the original example.
template<typename T>
struct writer
{
friend constexpr int inst_flag(inst_check_wrapper<T>)
{
return 0;
}
};
The switch toggler is identical to the one in the original example. It comes up with the definition for the switch of some type that you use. To allow for easy checking, add a helper switch inspector:
template <typename T, bool B = noexcept(inst_flag(inst_check_wrapper<T>()))>
constexpr bool is_instantiated()
{
return B;
}
Finally, the type "registers" itself as initialized. In my case:
template <typename T>
struct MyStruct
{
template <typename T1 = T, int = sizeof(writer<MyStruct<T1>>)>
MyStruct()
{}
};
The switch is turned on as soon as that particular constructor is asked for. Sample:
int main ()
{
static_assert(!is_instantiated<MyStruct<int>>(), "failure");
MyStruct<int> a;
static_assert(is_instantiated<MyStruct<int>>(), "failure");
}
Live on Coliru.
No, a compile time check for not instantiated classes is not possible. However you might establish a (static) map of instantiated classes (in debug build), which you can check at run time.
However, analyzing the linked binary by comparing a list of expected instantiated classes with actually instantiated classes should be possible (but that is past compile time and past my knowledge).
There's is no way to do that. So I would say: No.

passing function as parameter to template method of template class

The following code looks legitimate but doesn't compile
void f() {}
template<bool>
struct call_any
{
template<typename F>
static void call(F f) {}
};
template<bool B>
void call_f()
{
call_any<true>::call<void (&)()>(f); // OK
call_any<false>::call<void (&)()>(f); // OK
call_any<B>::call<void()>(f); // OK
call_any<B>::call<void (&)()>(f); // expected primary-expression before '>'
}
Why there is an error and what does it mean?
When you are dealing with types that are dependent on the template parameters within a template, the compiler doesn't know what kinds of things the members of that type are. Unless you specify otherwise, it assumes that the members are not types and not templates. Because of this, it is trying to treat < as a less-than operator, but it becomes impossible to parse the expression that way by the time it reaches the >.
To get rid of the error you should use this instead:
call_any<B>::template call<void (&)()>(f);
This tells the compiler explicitly that call is a template, so it should treat the < as the beginning of the template parameters and not a regular less-than operator.
This should use template as well:
call_any<B>::call<void()>(f);
The only reason you don't see the error on this line is that there is a way to parse it as a non-template:
(call_any<B>::call < void() ) > (f);
Although odd, it is syntatically valid, so the compiler gets past that line, and the first error you see is the one you mention. However, without the template keyword, you would eventually get an error once call_f was actually instantiated (probably -- there are weird ways it could work).
The first two examples are okay without using the template keyword. Since the type isn't dependent on the template parameters, it can be determined that call is a template while call_f is being parsed.
You might ask: "Why can't the compiler figure out it is a template? I've defined it as a template in the code right above!". The issue is specialization. You could specialize the template and do something completely different than what the primary template specifies:
template<>
struct call_any<false>
{
static const int call = 5;
};
This specialization could occur even after call_f is defined, so the compiler can't rely on what the primary template for call_any says when it is parsing call_f.

Why should the member function declarations of a class template be all well-formed?

OK, suppose I want to check whether the template parameter has a nested type/typedef XYZ.
template <class T>
struct hasXZY
{
typedef char no;
typedef struct { char x[2]; } yes;
template <class U>
static yes f(typename U::XYZ*);
template <class /*U*/>
static no f(...);
enum {value = sizeof(f<T>(0))==sizeof(yes)};
};
Works fine, as expected.
Now consider this:
template <class T>
struct hasXZY
{
typedef char no;
typedef struct { char x[2]; } yes;
static yes f(typename T::XYZ*);
static no f(...);
enum {value = sizeof(f(0))==sizeof(yes)};
};
hasXYZ<int> now results in a compile-time error. OK, f is not a template function. But on the other hand when hasXYZis instantiated for int via hasXYZ<int>::value, the compiler could easily just exclude f(int::XYZ*) from candidate list. I just don't understand why a failure in the instantiation of a member functions declaration in a class template must make the whole class instantiation fail. Any ideas?
Edit: My question is: why should the member function declararions be all well-formed? Since the compiler instantiates the methods only upon their usage, why does it need correct declaration. Consider the above example2 as a possible use-case of this feature.
SFINAE is used only when creating a candidate set for a function overload resolution. In your first example, you are calling the overloaded f() function, and the first one is excluded thanks to SFINAE.
In your second example, when instantiate hasXZY, all its members must be well defined, and the substitution of the template parameter must not fail. It does for int::XYZ.
Members will not be excluded from the class because of a substitution failure.
I'm not a C++ language lawyer, but I'll have a go at this.
In your second example, the member functions must be well-defined because they are no longer template functions once hasXZY is instantiated for int. To convince yourself of this, do the substitution for T "by hand":
struct hasXYZ
{
typedef int T;
typedef char no;
typedef struct { char x[2]; } yes;
static yes f(T::XYZ*);
static no f(...);
enum {value = sizeof(f(0))==sizeof(yes)};
};
int main()
{
std::cout << hasXYZ::value << "\n";
}
and observe that this fails to compile, with the same compiler error as before (in GCC, at least):
foo.cc:9: error: ‘T’ is not a class or namespace
By contrast, the first example compiles and behaves as expected after manual instantiation; the f members are still templated on U.
Edit: My question is: why should the member function declararions be all well-formed? Since the compiler instantiates the methods only upon their usage, why does it need correct declaration. Consider the above example2 as a possible use-case of this feature.
When implicitly instantiating a class template specialization, the compiler has to inspect the complete declarator of that member because it needs to know basic information about the declaration. Such can contribute to the size of the class template specialization.
If inspecting the declaration part will find out it's declaring a data-member, the sizeof value of the class will possibly yield a different value. If you would have declared a function pointer instead, this would be the case
yes (*f)(typename T::XYZ*);
The C++ language is defined in such a way that the type of a declaration is known only once the whole declaration is parsed.
You can argue that you put static there, and thus in this case this is not needed to compute its size. But it is needed for name-lookup to know what a name hasXZY<T>::f refers to and that there was declared a name f at all. The compiler will not instantiate the definition of hasXYZ::f, but it will only instantiate the non-definition part of the declaration, to gets its type and adding its name to the class type for name lookup purposes. I believe supporting delayed-instantiation for declaration of names in particular cases where it would possibly work would complicate implementation of C++ compilers and the C++ spec even more, for no comparable benefit.
And finally, in your example where you attempt to call it, the compiler has to instantiate the declaration, because it needs to lookup the name f, and for this it needs to know whether that declaration is a function or something else. So I really even theoretically can't see a way your example could work without instantiating the declaration. Note that in any case, these will not instantiate a definition of the function.