使用"std::enable_if_t" "function template has already been defined"

"function template has already been defined" using "std::enable_if_t"

本文关键字:has already defined been template if std enable 使用 function      更新时间:2023-10-16

我正在尝试使用std::enable_if_t根据传递给它的类型的特征来切换模板函数的实现。

下面是一个示例:

#include <iostream>
#include <type_traits>
// Enable if "T" is integral
template <typename T,
typename = std::enable_if_t<std::is_integral_v<T>>
>
void print(T value)
{
std::cout << "Integral: " << value << std::endl;
}
// Enable if "T" is not integral
template <typename T,
typename = std::enable_if_t<!std::is_integral_v<T>>
>
void print(T value)
{
std::cout << "Not Integral: " << value << std::endl;
}
int main()
{
int i = 42;
print(i);
double d = 42.0;
print(d);
}

问题是,这无法编译声明:

'

void print(T(':函数模板已经定义。

这对我来说感觉很奇怪,因为std::is_integral_v<T>!std::is_integral_v<T>永远不会同时评估为 true,因此每当启用一个实现时,都应该禁用另一个实现。

为什么这不起作用?解决此问题并获得我正在寻找的功能的最佳方法是什么?

CPP 参考:

一个常见的错误是声明两个仅不同的函数模板 在其默认模板参数中。这不起作用,因为 声明被视为同一函数的重新声明 模板(函数中不考虑默认模板参数 模板等效性(。

/*** WRONG ***/
struct T {
enum { int_t,float_t } m_type;
template <typename Integer,
typename = std::enable_if_t<std::is_integral<Integer>::value>
>
T(Integer) : m_type(int_t) {}
template <typename Floating,
typename = std::enable_if_t<std::is_floating_point<Floating>::value>
>
T(Floating) : m_type(float_t) {} // error: treated as redefinition
};
/* RIGHT */
struct T {
enum { int_t,float_t } m_type;
template <typename Integer,
std::enable_if_t<std::is_integral<Integer>::value, int> = 0
>
T(Integer) : m_type(int_t) {}
template <typename Floating,
std::enable_if_t<std::is_floating_point<Floating>::value, int> = 0
>
T(Floating) : m_type(float_t) {} // OK
};

在模板类型中使用enable_if时应小心 命名空间范围函数模板的非类型参数。一些 ABI 像安腾 ABI 这样的规范不包括 非类型模板参数的实例化相关部分 重音,意思是两种不同功能的专业化 模板最终可能会使用相同的损坏名称并出错 链接在一起。例如:

// first translation unit
struct X {
enum { value1 = true, value2 = true };
};
template<class T, std::enable_if_t<T::value1, int> = 0>
void func() {} // #1
template void func<X>(); // #2
// second translation unit
struct X {
enum { value1 = true, value2 = true };
};
template<class T, std::enable_if_t<T::value2, int> = 0>
void func() {} // #3
template void func<X>(); //#4

函数模板 #1 和 #3 具有不同的签名,并且 不同的模板。尽管如此,#2 和 #4,尽管是 不同函数模板的实例化,具有相同的损坏 安腾C++ ABI (_Z4funcI1XLi0EEvv( 中的名称,意思是 链接器会错误地将它们视为同一实体。

修复:

#include <iostream>
#include <type_traits>
// Enable if "T" is integral
template <typename T,
std::enable_if_t<std::is_integral_v<T>, int> = 0
>
void print(T value)
{
std::cout << "Integral: " << value << std::endl;
}
// Enable if "T" is not integral
template <typename T,
std::enable_if_t<!std::is_integral_v<T>, int> = 0
>
void print(T value)
{
std::cout << "Not Integral: " << value << std::endl;
}
int main()
{
int i = 42;
print(i);
double d = 42.0;
print(d);
}

更好的是,使用概念:

#include <iostream>
#include <concepts>
// Enable if "T" is integral
template <std::integral T>
void print(T value)
{
std::cout << "Integral: " << value << std::endl;
}
// Enable if "T" is not integral
template <typename T>
void print(T value)
{
std::cout << "Not Integral: " << value << std::endl;
}
int main()
{
int i = 42;
print(i);
double d = 42.0;
print(d);
}