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

时间:2017-11-07 14:09:25

标签: c++ templates primitive-types

我正在开发一个小小的C ++项目,为此我创建了一个名为std::ostream的漂亮且方便的Logger包装器。

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

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,模板就像魅力一样。 声明

someLoggerInstance << 123 << 456ULL << "\n";

编译得很好。

但是,如果我将语句更改为

someLoggerInstance << 12.3 << "\n";

编译器对我说,模板无法实例化。

编译器的错误消息:

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_arithmetic<T>替换std::is_integral<T>并使用std::is_floating_point<T>添加第二个模板化函数,但这不会改变任何内容,实例化整数模板,但浮点模板是不会导致与上面相同的错误消息。

如果我为类型double

创建了额外的重载
friend Logger& operator<<(Logger& logger, const double& logMessage) {
    return logger << std::to_string(logMessage);
}

问题变得更糟,从那时起,试图在最后通过"\n"的编译器让我感到恼火:

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

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

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

<小时/> 的修改

感谢您的快速帮助。

现在改变了这样的模板:

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);

3 个答案:

答案 0 :(得分:3)

T为双倍时,此事std::enable_if_t<std::is_arithmetic<T>::value, T>也会解析为double

但是明确禁止非类型模板参数为浮点类型。您问题的正确最小示例是:

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

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

std::enable_if_t解析为有效类型,例如您使用0初始化的指针或int

答案 1 :(得分:2)

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

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

答案 2 :(得分:2)

要解决您的第一个问题,替代SFINAE将使用std::enable_if_t来允许返回类型的替换失败...

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<char>::valuetrue所以您需要取消该案件的资格。