You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

std::type_identity处理可变参数列表的标准行为问询

关于std::type_identity在可变参数推导中行为的C++标准解读

问题背景

std::type_identity的核心作用是提供非推导上下文,避免模板参数被自动推导。但在测试其与可变参数列表结合的推导行为时,不同编译器出现了分歧:

  • 第一个bar调用可在GCC和MSVC中编译通过
  • 第二个bar调用仅能在MSVC中编译通过

需要明确C++标准下的正确行为。

示例代码

#include <type_traits>
 
struct in_between{};

template <typename... T>
struct args_tag
{
    using type = std::common_type_t<T...>;
};

template <typename... T>
void bar(args_tag<T...>, std::type_identity_t<T>..., int, std::type_identity_t<T>...) {}

template <typename... T>
void bar(args_tag<T...>, std::type_identity_t<T>..., in_between, std::type_identity_t<T>...) {}

// example
int main() {
    bar(args_tag<int, int>{}, 4, 8, 15, 16, 23);
    bar(args_tag<int, int>{}, 4, 8, in_between{}, 16, 23);
}

标准规则与行为分析

根据C++标准的模板参数推导规则:

  1. 模板参数的确定优先级:第一个函数参数args_tag<T...>是模板特化类型,编译器可直接从实参args_tag<int, int>{}推导出模板参数包T...为int, int。
  2. 非推导上下文的处理:std::type_identity_t<T>本质是typename std::type_identity<T>::type,属于标准定义的非推导上下文。这类上下文不会触发模板参数推导,编译器会直接使用已通过其他参数确定的T...结果。

针对两个调用的具体分析:

  • 第一个bar调用:
    推导出T... = int, int后,函数参数列表展开为args_tag<int, int>, int, int, int, int, int,与调用传入的参数完全匹配,编译通过符合标准。
  • 第二个bar调用:
    同理,推导出T... = int, int后,函数参数列表展开为args_tag<int, int>, int, int, in_between, int, int,与调用传入的参数完全匹配,同样应当编译通过。

结论

根据C++标准,两个bar调用都应该编译通过。MSVC的行为符合标准要求,GCC对第二个调用的编译失败属于编译器实现bug。

内容的提问来源于stack exchange,提问作者Sergey Kolesnik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 05:12:37