我有两个都具有单参数模板化构造函数的类。一个是整数类型的全部,另一个是用于绑定任何可迭代对象的。对于每种类型的特定函数,我都有两个重载。如果我使用整数类型或字符串或至少可用于其中 个类的函数调用该函数,则会收到有关调用歧义的错误。
#include <string>
class A {
public:
template <typename Iterable>
A(Iterable it) : s(it.begin(), it.end()) {}
private:
std::string s;
};
class B {
public:
template <typename Integer>
B(Integer i) : i(i + 1) {}
private:
int i;
};
void Use(A a)
{
// some thing
}
void Use(B b)
{
// some other thing
}
int main(void)
{
Use(0);
return 0;
}
编译器似乎对多态性的研究还不够多,无法确定确实只有一种可能的解决方案。难道是因为在函数重载之前“解析了”模板吗?如何给编译器一些帮助?
答案 0 :(得分:5)
编译器似乎对多态性的研究还不够多,无法确定确实只有一种可能的解决方案。
请注意,overload resolution是基于功能模板的签名执行的,包括功能名称,功能参数,模板参数等;但不会在overload resolution期间检查实现(例如函数体)。
您可以应用SFINAE来设置构造器模板可以接受的类型的限制,方法是添加另一个具有默认值的模板参数。例如
template <typename Iterable, typename = std::void_t<decltype(std::declval<Iterable>().begin()),
decltype(std::declval<Iterable>().end())>>
A(Iterable it) : s(it.begin(), it.end()) {}
和
template <typename Integer, typename = std::void_t<decltype(std::declval<Integer>() + 1)>>
B(Integer i) : i(i + 1) {}
答案 1 :(得分:1)
遵循SFINAE规则时,编译器不考虑该方法的实现。换句话说,它看到了接受单个参数的A类构造函数的声明。
如果希望SFINAE消除此选择,则需要将未能替换的表达式移至函数签名。