Due to implicit conversions, C++ allows us to call functions with arguments that don’t make sense. For example, the program below will successfully compile even though it makes no sense. The compiler doesn’t even throw an error or warning.
#include <iostream>
void setVolume(int level)
{
std::cout << "Volume set to " << level << "mm." << '\\n';
}
int main()
{
setVolume(10); // sensible
setVolume(true); // compiles, but semantically wrong
setVolume('A'); // compiles, but semantically wrong
}
// Output
Volume set to 10mm.
Volume set to 1mm.
Volume set to 65mm.
Even though implicit conversions assists us, in this situation it is biting us in the back.
What is desirable is to inform the compiler that this function call may not be used.
Deleting a function using the = delete specifier
We can use = delete to tell the compiler if this function is called with a particular type, DO NOT EXECUTE IT.
Let’s refactor the program above.
#include <iostream>
void setVolume(int level)
{
std::cout << "Volume set to " << level << "mm." << '\\n';
}
void setVolume(bool) = delete;
void setVolumne(char) = delete;
int main()
{
setVolume(10); // sensible
setVolume(true); // compiles, but semantically wrong
setVolume('A'); // compiles, but semantically wrong
}
// Output
/tmp/qRj9GbEKDx/main.cpp:14:14: error: use of deleted function 'void setVolume(bool)'
14 | setVolume(true); // compiles, but semantically wrong
When a match is made to a deleted function, the compiler throws an error. This way, we can enforce the argument type. This constrains the ways the caller can call the function.
Deleting all non-matching overloads
Their maybe situations where you want the argument type to exactly match the parameter type. In this situation, we can use function templates.
In the example below, setVolume() can only be called with an int. All other overloads are deleted
#include <iostream>
void setVolume(int level)
{
std::cout << "Volume set to " << level << "\\n";
}
template <typename T>
void setVolume(T) = delete;
int main()
{
setVolume(10); // OK: Exact parameter match
setVolume(true); // error
setVolume('A'); // error
setVolume(10.5); // error
}
This is a good tactic to enforce API’s.
In Conclusion
= delete lets you reject specific function calls at compile time, thereby enforcing how the API should be used.
This is valuable since C++’s implicit conversions allow calls that are technically valid but semantically wrong.