C ++模板函数重载解析bug

时间:2016-12-15 23:51:02

标签: c++ templates

namespace Random
{
    std::mt19937 engine_{ std::random_device{}() };

    template<class T, class = std::enable_if_t<std::is_integral<T>::value>>
    auto get(T from, T to)
    {
        return std::uniform_int_distribution<T>{from, to}(engine_);
    }

    template<class T, class = std::enable_if_t<std::is_same<T, float>::value>>
    auto get(T from, T to)
    {
    return std::uniform_real_distribution<T>{from, to}(engine_);
    }

}
int main()
{
    std::cout.sync_with_stdio(false);
    std::cout.setf(std::ios_base::boolalpha);
    std::cout << Random::get<float>(1.0f, 2.5f);//COMPILE TIME ERROR
    std::cin.get();
}

编译器输出: 18:4:错误:重新定义'模板T Random :: get(T,T)' 12:4:注意:'模板T Random :: get(T,T)'先前在这里声明  在函数'int main()'中: 28:44:错误:没有匹配函数来调用'get(float,float)' 28:44:注意:候选人是: 12:4:注意:模板T Random :: get(T,T) 12:4:注意:模板参数扣除/替换失败:

这项工作很好:

#include <type_traits>
#include <random>
#include <iostream>

namespace Random
{
    std::mt19937 engine_{ std::random_device{}() };

    template<class T, class = std::enable_if_t<std::is_integral<T>::value>>
    auto get(T from, T to)
    {
        return std::uniform_int_distribution<T>{from, to}(engine_);
    }

    template<class T, class = std::enable_if_t<std::is_same<T, float>::value>>
    T get(T from, T to)
    {
    return std::uniform_real_distribution<T>{from, to}(engine_);
    }

}
int main()
{
    std::cout.sync_with_stdio(false);
    std::cout.setf(std::ios_base::boolalpha);
    std::cout << Random::get<float>(1.0f, 2.5f);//GOOD
    std::cin.get();
}

和此:

#include <type_traits>
#include <random>
#include <iostream>

namespace Random
{
    std::mt19937 engine_{ std::random_device{}() };

    template<class T, class = std::enable_if_t<std::is_integral<T>::value>>
    auto get(T from, T to)
    {
        return std::uniform_int_distribution<T>{from, to}(engine_);
    }

    template<class T>
    std::enable_if_t<std::is_same<T, float>::value, T>
    get(T from, T to)
    {
        return std::uniform_real_distribution<T>{from, to}(engine_);
    }

}
int main()
{
    std::cout.sync_with_stdio(false);
    std::cout.setf(std::ios_base::boolalpha);
    std::cout << Random::get<float>(1.0f, 2.5f);//GOOD
    std::cin.get();
}

为什么编译器在第一个示例中无法解析此解决方案?

1 个答案:

答案 0 :(得分:0)

默认参数不是签名的一部分,因此您需要进行比较

template <typename T, typename>
auto get(T, T) { /* implementation2 */ }

VS

template <typename T, typename>
auto get(T, T) { /* implementation1 */ }

被视为相同的签名(即使推断的返回类型不同)

在您的工作示例中,您有不同的签名(即使自动推断为T)

template<class T, typename>
T get(T, T) { /* implementation2 */ }

VS

template <typename T>
std::enable_if_t<std::is_same<T, float>::value, T>
get(T, T) { /* implementation2 */ }

auto
由于SFINAE,这个电话并不含糊。

另一种允许template<class T, std::enable_if_t<std::is_integral<T>::value>* = nullptr> auto get(T from, T to) { return std::uniform_int_distribution<T>{from, to}(engine_); } template<class T, std::enable_if_t<std::is_same<T, float>::value>* = nullptr> auto get(T from, T to) { return std::uniform_real_distribution<T>{from, to}(engine_); } 返回类型并使用SFINAE的方法是

`curl -s -u #{username}:#{password} #{HTTPS_PAGE_URL}`