编译器bug ?

问题描述

两个结构几乎相同的模板实现,一个能正常工作,另一个在 VS2019 和 GCC 中都会报错。

最小化测试代码

cpp 复制代码
// bug_report.cpp
#include <type_traits>
#include <string>

template<typename T> struct Type2Type { using type = T; };
template<typename T1, typename T2> struct IsSameType : std::false_type {};
template<typename T> struct IsSameType<T, T> : std::true_type {};

// 工作正常的版本
template<size_t idx, typename TList> struct FindNthTypeInTypeList;
template<typename T, template <typename ...> class TList, typename ... Types>
struct FindNthTypeInTypeList<0,TList<T, Types...>> : public Type2Type<T> {};
template<size_t idx, template <typename ...> class TList, typename T, typename ... Types>
struct FindNthTypeInTypeList<idx, TList<T, Types ...>> : public FindNthTypeInTypeList<idx-1, TList<Types ...>> {};
template<size_t idx, typename TList> using FindNthTypeInTypeList_t = typename FindNthTypeInTypeList<idx, TList>::type;

// 不能工作的版本
template<size_t idx, typename TList> struct GetAllTypesFromIdx;
template<template <typename ...> class TList, typename ... Types>
struct GetAllTypesFromIdx<0, TList<Types...>> : public Type2Type<TList<Types...>> {};
template<size_t idx, typename T, template <typename ...> class TList, typename ... Types>
struct GetAllTypesFromIdx<idx, TList<T, Types...>> : public GetAllTypesFromIdx<idx-1, TList<Types...>> {};
template<size_t idx, typename TList> using GetAllTypesFromIdx_t = typename GetAllTypesFromIdx<idx, TList>::type;

// 测试类型列表
template<typename...> struct TypeList {};
using tc_typeList = TypeList<int, char, std::string, char*>;

int main()
{
    // FindNthTypeInTypeList 测试 - 这些都能工作
    static_assert(IsSameType<FindNthTypeInTypeList_t<0, tc_typeList>, int>::value);
    static_assert(IsSameType<FindNthTypeInTypeList_t<1, tc_typeList>, char>::value);
    static_assert(IsSameType<FindNthTypeInTypeList_t<2, tc_typeList>, std::string>::value);
    static_assert(IsSameType<FindNthTypeInTypeList_t<3, tc_typeList>, char*>::value);
    static_assert(!IsSameType<FindNthTypeInTypeList_t<0, tc_typeList>, char>::value);

    // GetAllTypesFromIdx 测试 - 这些会报错
    static_assert(IsSameType<GetAllTypesFromIdx_t<0, tc_typeList>, TypeList<int, char, std::string, char*>>::value);
    // static_assert(IsSameType<GetAllTypesFromIdx_t<1, tc_typeList>, TypeList<char, std::string, char*>>::value);
    // static_assert(IsSameType<GetAllTypesFromIdx_t<2, tc_typeList>, TypeList<std::string, char*>>::value);
    // static_assert(IsSameType<GetAllTypesFromIdx_t<3, tc_typeList>, TypeList<char*>>::value);
}

错误信息

在 VS2019 和 GCC 中都会报错:

cpp 复制代码
1>C:\...\MiniMPL\sources\UnitTest\UT_MiniMPL\src\tc_typeList_cpp11.cpp(135,9): error C2752: 'MiniMPL::GetAllTypesFromIdx<0,UnitTest::tc_typeList>': more than one partial specialization matches the template argument list
1>C:\...\MiniMPL\sources\MiniMPL\include\MiniMPL\typeList_cpp11.hpp(56,105): message : could be 'MiniMPL::GetAllTypesFromIdx<0,TList<Types...>>'
1>C:\...\MiniMPL\sources\MiniMPL\include\MiniMPL\typeList_cpp11.hpp(58,105): message : or       'MiniMPL::GetAllTypesFromIdx<idx,TList<T,Types...>>'
1>C:\...\MiniMPL\sources\UnitTest\UT_MiniMPL\src\tc_typeList_cpp11.cpp(135): message : see reference to alias template instantiation 'MiniMPL::GetAllTypesFromIdx_t<0,UnitTest::tc_typeList>' being compiled
1>C:\...\MiniMPL\sources\MiniMPL\include\MiniMPL\typeList_cpp11.hpp(59,176): error C2794: 'type': is not a member of any direct or indirect base class of 'MiniMPL::GetAllTypesFromIdx<0,UnitTest::tc_typeList>'
1>C:\...\MiniMPL\sources\UnitTest\UT_MiniMPL\src\tc_typeList_cpp11.cpp(135,9): error C2938: 'MiniMPL::GetAllTypesFromIdx_t' : Failed to specialize alias template

问题分析

  1. 两个模板实现 `FindNthTypeInTypeList` 和 `GetAllTypesFromIdx` 的结构几乎完全相同

  2. 它们都有:

  • 一个 `idx=0` 的特化

  • 一个通用的递归特化

  • 相同的类型列表处理方式

  1. `FindNthTypeInTypeList` 能正常工作,所有测试都通过

  2. `GetAllTypesFromIdx` 在 VS2019 和 GCC 中都会报错

预期行为

  • 两个模板都应该能正常工作

  • `FindNthTypeInTypeList` 应该返回指定索引的类型

  • `GetAllTypesFromIdx` 应该返回从指定索引开始的所有类型

实际行为

  • `FindNthTypeInTypeList` 按预期工作

  • `GetAllTypesFromIdx` 报错,认为两个特化是同等特化的

环境信息

  • 编译器:VS2019 和 GCC

  • 标准:C++11 或更高

  • 操作系统:Windows/Linux

可能的解决方案

  1. 使用 SFINAE 来限制第二个特化只在 `idx>0` 时匹配

  2. 重新设计模板特化,使其特化规则更明确

  3. 等待编译器更新修复这个 bug

相关推荐
皓月斯语14 分钟前
B3865 [GESP202309 二级] 小杨的 X 字矩阵 题解
开发语言·c++·矩阵·题解
paeamecium2 小时前
【PAT甲级真题】- Rational Sum (20)
数据结构·c++·python·算法·pat考试·pat
王维同学10 小时前
Winsock 协议与名称空间 Provider 目录
网络·c++·windows·安全
拳里剑气11 小时前
C++算法:BFS解决FloodFill算法
c++·算法·bfs·宽度优先
爱写代码的小朋友12 小时前
从零开始学 Win32 API:C++ 窗口编程实战(VS Code + MinGW-w64 命令行详解)
开发语言·c++
小小晓.12 小时前
C++:语句和作用域
开发语言·c++
fqbqrr12 小时前
2607C++,soui,xplayer视频播放器
c++·soui
zh路西法13 小时前
【10天速通ROS2-PX4无人机】(四) 关掉GPS和气压计,纯激光定位还能飞吗
c++·无人机·px4·ros2·卡尔曼滤波·fastlio2
yyds_yyd_1008614 小时前
1464. 数组中两元素的最大乘积(2026.07.27)
数据结构·c++·算法·leetcode
王老师青少年编程16 小时前
csp信奥赛C++高频考点专项训练:【排序算法】案例7:最高分数的学生姓名
c++·排序算法·csp·高频考点·信奥赛·最高分数的学生姓名