调用具有可转换类型的重载函数时

时间:2019-07-02 05:28:48

标签: c++ templates constructor overloading overload-resolution

我有两个具有单参数模板化构造函数的类。一个是整数类型的全部,另一个是用于绑定任何可迭代对象的。对于每种类型的特定函数,我都有两个重载。如果我使用整数类型或字符串或至少可用于其中 个类的函数调用该函数,则会收到有关调用歧义的错误。

#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;
}

编译器似乎对多态性的研究还不够多,无法确定确实只有一种可能的解决方案。难道是因为在函数重载之前“解析了”模板吗?如何给编译器一些帮助?

2 个答案:

答案 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) {} 

LIVE

答案 1 :(得分:1)

遵循SFINAE规则时,编译器不考虑该方法的实现。换句话说,它看到了接受单个参数的A类构造函数的声明。

如果希望SFINAE消除此选择,则需要将未能替换的表达式移至函数签名。