C ++模棱两可的重载

时间:2018-07-14 13:50:49

标签: c++ templates overloading

请考虑以下内容:

#include <string>

template <typename T, 
    typename std::enable_if<(
        std::is_integral<T>::value 
        && !std::is_same<T, bool>::value
    )>::type = 0>
void add(T val)
{
}

void add(bool val)
{
}

void add(const char* val)
{
}

int main()
{
    add(true);
    add("hi");
    add(0);
}

编译器抱怨add(0);不明确:

  

[x86-64 clang 6.0.0#1]错误:对“ add”的调用不明确

我想出这一点是因为0可隐式转换为boolconst char*。但是,我希望编译器选择模板方法而不必强制转换0(即add((int)0);)或指定模板类型(即add<int>(0);)。

我还尝试将模板签名更改为:

template <typename T, 
    typename std::enable_if<(
        std::is_integral<T>::value 
        && !std::is_same<T, bool>::value
        && !std::is_same<T, unsigned char>::value
    )>::type = 0>
void add(T val)
...

但这也无济于事。如何使它按我想要的方式工作?

谢谢!

1 个答案:

答案 0 :(得分:4)

enable_if具有第二个模板参数,默认为void,并在条件为type时定义truetypename void = 0无法编译,这就是为什么该函数不能成为重载解析的一部分的原因。但是typename int = 0确实可以编译,因此传递int会使函数成为重载重分解的一部分:

template <typename T,
    typename std::enable_if<(
        std::is_integral<T>::value 
        && !std::is_same<T, bool>::value
        && !std::is_same<T, unsigned char>::value
    ), int>::type = 0>
void add(T val)
{
}

您也可以这样写,而无需传递第二个参数,我认为这更简单:

template <typename T,
    typename = typename std::enable_if<(
        std::is_integral<T>::value 
        && !std::is_same<T, bool>::value
    )>::type>
void add(T val)
{
}

void add(bool val)
{
}

void add(const char* val)
{
}

int main()
{
    add(true);
    add("hi");
    add(0);       // A
    add<int>(0);  // B
    // A and B call the same function
}