I'm trying to write an RAII-compliant resource wrapper, and I'm getting stuck on how to form the semantics of the template parameters.
For example, I could write a function to delete my resource:
void int_cleaner(int val) {
std::cout << "Value of " << val << " has been cleaned up." << std::endl;
}
Or I could write it as a Functor:
struct int_deleter {
void operator()(int val) const {
std::cout << "Value of " << val << " has been cleaned up." << std::endl;
}
};
But here's where I get stuck: if I want to pass this to my resource wrapper, I have to change how the template parameter is defined.
If I write resource like this:
template<typename T, typename Deleter>
class resource {
};
This works fine with a functor, but not with the function itself.
int main() {
resource<int, int_deleter> res; //Compiles fine
//resource<int, int_cleaner> res2; //Does Not Compile
return 0;
}
Conversely, if I write the template parameters like this:
template<typename T>
using deleter_t = void(*)(T);
template<typename T, deleter_t<T> Deleter>
class resource {
};
int main() {
//resource<int, int_deleter> res; //Does Not Compile
resource<int, int_cleaner> res2; //Compiles fine
return 0;
}
Now, I could write both versions of the code, but there's two reasons I don't want to do that:
- I'd just be duplicating the definition for
resource, and if I need to make a change to one, I need to make changes to the other as well. - The version that accepts function pointers won't accept a version like
void cleaner(T const&), because that won't bind tovoid(*)(T). So I'd also need to make two or three more versions so that I can handleT,T&,T const&, andT&&.
How can I write the resource wrapper in such a way that minimizes code duplication, especially given that the deletion mechanism is going to vary between the functor version and the function pointer version?
//example:
template<typename T>
using deleter_t = void(*)(T);
template<typename T, deleter_t<T> Deleter>
class resource {
~resource() {Deleter(val);}
};
template<typename T, typename Deleter>
class resource {
~resource() {Deleter{}(val);}//Note the subtle syntax change
};