c ++模板实例化可以使用int,long等,但不能使用float,double等

c++ template instantiation works with int, long, etc. but not float, double, etc

我正在研究一个小C++项目,为此我创建了一个漂亮的、方便的EDCOX1×0封装,称为EDCOX1×1。

在类中,我定义了一个模板化的运算符:

1
2
3
4
template<typename T, typename std::enable_if_t<std::is_arithmetic<T>::value, T> = 0>
friend Logger& operator<<(Logger& logger, const T& logMessage) {
    return logger << std::to_string(logMessage); // there is also an operator overload which takes a std::string& as argument.
}

当模板显示为整型时,如intlong,模板的工作方式就像一个魅力。所以声明

1
2
someLoggerInstance << 123 << 456ULL <<"
"
;

编译得很好。

但是如果我把声明改为

1
2
someLoggerInstance << 12.3 <<"
"
;

编译器冲我大喊,模板无法实例化。

来自编译器的错误消息:

1
Candidate template ignored: substitution failure [with T = double]: a non-type template parameter cannot have type 'typename std::enable_if_t::value, double>' (aka 'double')

问题出在哪里?

我试图用std::is_integral替换std::is_arithmetic并使用std::is_floating_point添加第二个模板化函数,但这并没有改变任何东西,整体模板被实例化,但浮点模板没有,导致与上面相同的错误消息。

如果我为double类型创建额外的重载

1
2
3
friend Logger& operator<<(Logger& logger, const double& logMessage) {
    return logger << std::to_string(logMessage);
}

问题变得更严重,因为编译器试图在最后传递"
"
,用以下消息来烦扰我:

1
Candidate function not viable: no known conversion from 'const unsigned char [1]' to 'const double' for 2nd argument

1
Candidate function not viable: no known conversion from 'const unsigned char [1]' to 'const std::string' (aka 'const basic_string, allocator >') for 2nd argument

任何帮助或建议都很好!谢谢您!


编辑

谢谢你的快速帮助。

现在更改模板如下:

1
2
template<typename T, typename TEnable = std::enable_if_t<std::is_arithmetic<T>::value && !std::is_same<T, char>::value, T>>
friend Logger& operator<<(Logger& logger, const T& logMessage);

T是一个双精度数时,这个问题std::enable_if_t::value, T>也解决为double

但非类型模板参数显式地不允许是浮点类型。对于您的问题,正确的最小示例是:

1
2
template<double d> // this is ill-formed
void foo() {}

其基本原理是,模板是根据非类型参数的确切值专门化的。这是一个类型的问题,直接相等的比较是有问题的。

只需让std::enable_if_t解析为一个有效的类型,例如一个指针或一个用0初始化的int


为了解决第一个问题,另一种方法是使用std::enable_if_t来允许返回类型的替换失败…

1
2
3
4
5
6
template <typename T>
std::enable_if_t<std::is_arithmetic<T>::value, Logger&>
friend operator<<(Logger& logger, const T& logMessage)
{
    return logger << std::to_string(logMessage);
}

你的第二个问题是因为std::is_arithmetic::valuetrue,所以你需要取消这个案子的资格。


更新模板以使用类型模板参数:

1
2
3
4
5
6
7
8
template
<
    typename T
,   typename TEnabled = typename std::enable_if_t<std::is_arithmetic<T>::value, T>
>
friend Logger & operator <<(Logger & logger, const T & logMessage) {
    return logger << std::to_string(logMessage);
}