为什么在这个简单的示例中SFINAE不起作用?如果我注释掉模板化的“添加”,则代码可以编译。为什么在替换失败后编译器不尝试调用非模板的“ add”?
我正在使用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);
}
是否可以在没有冗长的样板代码(例如std :: enable_if等)的情况下使该代码正常工作?
答案 0 :(得分:1)
来自cppreference:
仅函数类型或其模板参数类型[或其显式说明符(自C ++ 20起)]的直接上下文中的类型和表达式失败是SFINAE错误
在这里,失败发生在函数主体中,因此它是替换失败,但不是在SFINAE上下文中发生-而是错误。
这些概念旨在帮助减轻这种繁琐的工作量,因此,如果编译器已经支持它们,则可以尝试使用它们。
答案 1 :(得分:1)
如果您将第一个功能更改为:
template <class ptr_t>
void add(std::shared_ptr<ptr_t>& b) {
buttons.insert(b);
}
然后您的代码将编译并按预期工作。
注意两点:
template
。const
对象。有效的模板函数比需要一些“转换”的非模板函数更受欢迎。
顺便说一句,您的示例中没有SFINAE。实际上,template<class container_t> void add(container_t& c)
是可以接受的匹配。