当我尝试使用以下元函数来检索元组的第一种类型时,代码可以用GCC编译,但不能用Clang编译。关于这个小片段,我有两个问题。
- 这是合法的C++代码吗?为什么?或者为什么不呢
- 是否有适用于两个编译器的变通方法(或正确的替代方法(
#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;
};