You cannot write a template function specialization for which no template argument makes the body valid in C++. The result if you do so is an ill formed program with no diagnostic required. This includes the primary specialization.
So most of the answers here are simply undefined behaviour. They may work, but they are not valid C++. They may work today, but after a library upgrade a compiler upgrade or a different build target they could fail in completely different and surprising ways. Relying on UB with no strong reason is a bad idea.
On the plus side, we can do away with template specialization and fix your problem in one fell swoop:
template<class T>struct tag_t{}; // may need `constexpr tag_t(){}` on some compilers
template<class T>constexpr tag_t<T> tag{};
template<class T, class F>
constexpr T my_numeric_cast(F, tag_t<F>)=delete; // generates compile time error
constexpr float my_numeric_cast(int i, tag_t<float>) { return i; } // not a template! Could be if you want it to be.
template<typename To, typename From>
constexpr To my_numeric_cast(From f){
return my_numeric_cast(f, tag<To>);
}
and done.
=delete
generates friendly messages. Program is well formed. Implementing casts is no longer a specialization. You can even implement it in the namespace of a type being cast to or from as ADL is enabled.
If you solve a problem with template function specialization, reconsider. They are fragile, do not work like class template specialization or function overloading (while looking like both of them!), and usually are not the best solution to anything. There are exceptions when it may be a good idea, but they are quite rare, and given how rare they are avoiding the quirky feature may still be worth it.