Consider the following system:
template<typename T>
struct wrapper
{
operator T * () { return nullptr; }
};
template<typename Ret, typename T>
Ret func(T);
template<>
int func(float * in)
{
std::cout << "long";
}
template<>
long func(float * in)
{
std::cout << "int";
}
The purpose of the wrapper is to allow it to decay to the type it is templated to (it is a wrapper around a buffer of the type). Moreover, i have a set of functions that are templated specializations of a template. This is to circumvent the usual error when overloading based on only the return type.
This doesn't work though, as noted here:
// the following should work, but doesn't because it's instantiating
// the func<ret, wrapper<float>> which doesn't exist resulting in a linker error
// instead of selecting the int func(float *) overload
wrapper<float> w;
func<int>(w);
Conversely, i would like this to generate a compile-time error (but again, it's generating a link-time error):
// the following should generate a compile-time error
// since no explicit overload for int func(int *) exists
wrapper<int> w2;
func<int>(w2);
So ideally, i would like to disable the original template (maybe through sfinae if this is possible?) such that the overload resolution only considers the explicit specializations, and generates a compile-time error if no match is found. Can this be done?
A portable solution between clang and msvc is a must, but I'm using the newest versions of both.
Another approach may be to use static_assert:
While Jarod's answer solved one of the problems, i still needed a way to overload the function arguments (which in that case would generate 'no matching template' errors) - i probably didn't state that in the OP.
It dawned on me, that the parameter type(s) are always dependant on the return type. I could then construct a helper-struct, that would do the sfinae:
and then the default template would look like this:
and the overloads could then be constructed like this:
-without problems. Note that any other combination of returns and parameter types would be invalid (since they are not a specialization of the original template, which only considers the options i give it). This also reduces the only overload resolutions to the two overloads, and thus makes this possible:
The added bonus of course is the compiler recognizes the error at the call / instantiation with a correct error message, instead of some random static_assert / linker errors. Success!
If you do
it works as expected: Live example