Reputation: 115
Why SFINAE doesn't work in this simple example? If I comment out the templated 'add' the code compiles ok. Why compiler doesn't try to call non-template 'add' after the substitution failure?
I'm using MSVS 2017.
#include <set>
#include <memory>
struct button_t
{
virtual ~button_t() {}
};
struct up_down_button_t : button_t
{
};
struct gui_t
{
std::set<std::shared_ptr<button_t> > buttons;
void add(const std::shared_ptr<button_t>& b) {
buttons.insert(b);
}
template<class container_t>
void add(container_t& c) {
for (auto& i : c)
add(i);
}
} gui;
int main(int argc, char* argv[]) {
auto b = std::make_shared<up_down_button_t>();
gui.add(b);
}
Is it possible to make that code work without verbose boilerplate code such as std::enable_if etc?
Upvotes: 0
Views: 70
Reputation: 2623
If you change your first function to:
template <class ptr_t>
void add(std::shared_ptr<ptr_t>& b) {
buttons.insert(b);
}
Then your code will compile and works as expected.
Two things to notice:
template
.const
object.A valid template function would be preferred to a non template function that need some "conversion".
By the way, there is no SFINAE in your example. In fact, template<class container_t> void add(container_t& c)
is an acceptable match.
Upvotes: 1
Reputation: 1247
From cppreference:
Only the failures in the types and expressions in the immediate context of the function type or its template parameter types [or its explicit specifier (since C++20)] are SFINAE errors
Here, the failure happen in the body of the function, so it is a substitution failure, but not in SFINAE context - so it is an error.
Concepts are intended to help making this less boilerplate heavy, so you could try using them if your compiler support them already.
Upvotes: 1