C 模板功能过载分辨率错误

C++ template function overload resolution bug

本文关键字:分辨率 错误 功能      更新时间:2023-10-16
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();
}

为什么编译器无法在第一个示例中解析此分辨率?

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

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

vs

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

被视为相同的签名(即使推导的返回类型也有所不同)

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

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

vs

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

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

,由于Sfinae,呼叫不是模棱两可的。

允许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_);
}