编译器与简单元函数不一致



当我尝试使用以下元函数来检索元组的第一种类型时,代码可以用GCC编译,但不能用Clang编译。关于这个小片段,我有两个问题。

  1. 这是合法的C++代码吗?为什么?或者为什么不呢
  2. 是否有适用于两个编译器的变通方法(或正确的替代方法(
#include <tuple>
template<typename>
struct first_type;
template<template<typename, typename...> typename T, typename T1, typename... Ts>
struct first_type<T<T1, Ts...>>
{ using type = T1; };
template<typename T>
using first_type_t = typename first_type<T>::type;
using tuple_type1 = first_type_t<std::tuple<int, int, double>>;

实例


根据请求,Clang生成的错误消息:

<source>:12:1: error: implicit instantiation of undefined template
'first_type<std::tuple<int, int, double>>'
using first_type_t = typename first_type<T>::type;
^
<source>:14:21: note: in instantiation of template type alias
'first_type_t' requested here
using tuple_type1 = first_type_t<std::tuple<int, int, double>>;
^
<source>:4:8: note: template is declared here
struct first_type;
^

结论:

  • 如IWonderWhatThisAPI所回答;为了完全避免编译器的差异,只需放弃模板化模板参数至少有一个类型的要求
  • 正如Nathan Oliver所指出的;如果您需要元组的第一种类型(或者任何给定索引的类型(,只需使用std::tuple_element元函数即可
  • 正如HolyBlackCat所指出的;Clang对模板化模板参数执行的裁决似乎比标准的技术要求更严格。可以通过传递-frelaxed-template-template-args编译器标志来禁用此行为

暂时将结构声明更改为(从而消除不完整的类型(:

template<typename>
struct first_type {};

将您得到的错误更改为:

no type named 'type' in 'first_type<std::tuple<int, int, double>>'

这给了我们有价值的信息:编译器选择了模板的通用版本,这意味着Clang不认为元组是一个有效的template<typename,typename...>class来实例化first_type(这是真的——template<typename,typename...>class需要一个或多个参数,而元组也可以是空的(。正如评论中所指出的,这对标准本身并不重要,但Clang故意拒绝。

元组是template<typename...>class,所以…

template<template<typename...> typename T, typename T1, typename... Ts>
struct first_type<T<T1, Ts...>> {
using type = T1;
};

最新更新