使用“std::enable_if_t”“函数模板已被定义”[重复]

2024-03-13

我正在尝试使用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> and !std::is_integral_v<T>永远不会同时评估为 true,因此每当启用一个实现时,就应禁用另一个实现。

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


CPP参考 https://en.cppreference.com/w/cpp/types/enable_if:

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

/*** 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 像 Itanium ABI 这样的规范不包括 非类型模板参数的实例化相关部分 mangling,意味着两个不同函数的专业化 模板可能最终会出现相同的错误名称并且出现错误 链接在一起。例如:

// 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,尽管是 不同函数模板的实例化,具有相同的损坏 Itanium C++ ABI 中的名称 (_Z4funcI1XLi0EEvv),表示 链接器会错误地认为它们是同一实体。

Fix:

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

LIVE https://gcc.godbolt.org/z/X8NRZb

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用“std::enable_if_t”“函数模板已被定义”[重复] 的相关文章

  • C 编程 - 文件 - fwrite

    我有一个关于编程和文件的问题 while current NULL if current gt Id Doctor 0 current current gt next id doc current gt Id Doctor if curre
  • 通过 CMIS (dotCMIS) 连接到 SP2010:异常未经授权

    我正在使用 dotCMIS 并且想要简单连接到我的 SP2010 服务器 我尝试用 C 来做到这一点 如下所示http chemistry apache org dotnet getting started with dotcmis htm
  • Web 客户端和 Expect100Continue

    使用 WebClient C NET 时设置 Expect100Continue 的最佳方法是什么 我有下面的代码 我仍然在标题中看到 100 continue 愚蠢的 apache 仍然抱怨 505 错误 string url http
  • 在哪里可以找到列出 SSE 内在函数操作的官方参考资料?

    是否有官方参考列出了 GCC 的 SSE 内部函数的操作 即 头文件中的函数 除了 Intel 的 vol 2 PDF 手册外 还有一个在线内在指南 https www intel com content www us en docs in
  • 查找c中结构元素的偏移量

    struct a struct b int i float j x struct c int k float l y z 谁能解释一下如何找到偏移量int k这样我们就可以找到地址int i Use offsetof 找到从开始处的偏移量z
  • 为什么当实例化新的游戏对象时,它没有向它们添加标签? [复制]

    这个问题在这里已经有答案了 using System Collections using System Collections Generic using UnityEngine public class Test MonoBehaviou
  • 使用实体框架模型输入安全密钥

    这是我今天的完美想法 Entity Framework 中的强类型 ID 动机 比较 ModelTypeA ID 和 ModelTypeB ID 总是 至少几乎 错误 为什么编译时不处理它 如果您使用每个请求示例 DbContext 那么很
  • 在 ASP.NET 5 中使用 DI 调用构造函数时解决依赖关系

    Web 上似乎充斥着如何在 ASP NET 5 中使用 DI 的示例 但没有一个示例显示如何调用构造函数并解决依赖关系 以下只是众多案例之一 http social technet microsoft com wiki contents a
  • 带动态元素的 WPF 启动屏幕。如何?

    我是 WPF 新手 我需要一些帮助 我有一个加载缓慢的 WPF 应用程序 因此我显示启动屏幕作为权宜之计 但是 我希望能够在每次运行时更改屏幕 并在文本区域中显示不同的引言 这是一个生产力应用程序 所以我将使用非愚蠢但激励性的引言 当然 如
  • 创建链表而不将节点声明为指针

    我已经在谷歌和一些教科书上搜索了很长一段时间 我似乎无法理解为什么在构建链表时 节点需要是指针 例如 如果我有一个节点定义为 typedef struct Node int value struct Node next Node 为什么为了
  • 显示UnityWebRequest的进度

    我正在尝试使用下载 assetbundle统一网络请求 https docs unity3d com ScriptReference Networking UnityWebRequest GetAssetBundle html并显示进度 根
  • 如何设计以 char* 指针作为类成员变量的类?

    首先我想介绍一下我的情况 我写了一些类 将 char 指针作为私有类成员 而且这个项目有 GUI 所以当单击按钮时 某些函数可能会执行多次 这些类是设计的单班在项目中 但是其中的某些函数可以执行多次 然后我发现我的项目存在内存泄漏 所以我想
  • 转发声明和包含

    在使用库时 无论是我自己的还是外部的 都有很多带有前向声明的类 根据情况 相同的类也包含在内 当我使用某个类时 我需要知道该类使用的某些对象是前向声明的还是 include d 原因是我想知道是否应该包含两个标题还是只包含一个标题 现在我知
  • 垃圾收集器是否在单独的进程中运行?

    垃圾收集器是否在单独的进程中启动 例如 如果我们尝试测量某段代码所花费的进程时间 并且在此期间垃圾收集器开始收集 它会在新进程上启动还是在同一进程中启动 它的工作原理如下吗 Code Process 1 gt Garbage Collect
  • 这些作业之间是否存在顺序点?

    以下代码中的两个赋值之间是否存在序列点 f f x 1 1 x 2 不 没有 在这种情况下 标准确实是含糊不清的 如果你想确认这一点 gcc 有这个非常酷的选项 Wsequence point在这种情况下 它会警告您该操作可能未定义
  • Windows 窗体:如果文本太长,请添加新行到标签

    我正在使用 C 有时 从网络服务返回的文本 我在标签中显示 太长 并且会在表单边缘被截断 如果标签不适合表单 是否有一种简单的方法可以在标签中添加换行符 Thanks 如果您将标签设置为autosize 它会随着您输入的任何文本自动增长 为
  • 链接器错误:已定义

    我尝试在 Microsoft Visual Studio 2012 中编译我的 Visual C 项目 使用 MFC 但出现以下错误 error LNK2005 void cdecl operator new unsigned int 2
  • WPF/C# 将自定义对象列表数据绑定到列表框?

    我在将自定义对象列表的数据绑定到ListBox in WPF 这是自定义对象 public class FileItem public string Name get set public string Path get set 这是列表
  • cmake 将标头包含到每个源文件中

    其实我有一个简单的问题 但找不到答案 也许你可以给我指一个副本 所以 问题是 是否可以告诉 cmake 指示编译器在每个源文件的开头自动包含一些头文件 这样就不需要放置 include foo h 了 谢谢 CMake 没有针对此特定用例的
  • C# - OutOfMemoryException 在 JSON 文件上保存列表

    我正在尝试保存压力图的流数据 基本上我有一个压力矩阵定义为 double pressureMatrix new double e Data GetLength 0 e Data GetLength 1 基本上 我得到了其中之一pressur

随机推荐