【问题标题】:Compiler discrepancy with simple meta function编译器与简单元函数的差异
【发布时间】:2021-05-25 15:23:30
【问题描述】:

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

  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>>;

Live example


根据要求,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;
       ^

总结:

  • 由 IWonderWhatThisAPIDoes 回答;要完全规避编译器差异,只需放弃模板化模板参数的要求,使其至少具有单一类型。
  • 正如 Nathan Oliver 指出的那样;如果您需要元组的第一种类型(或者实际上是任何给定索引的类型),只需使用 std::tuple_element 元函数即可。
  • 正如 HolyBlackCat 指出的那样;似乎 Clang 关于模板化模板参数的规定比标准的技术要求更严格。可以通过传递 -frelaxed-template-template-args 编译器标志来禁用此行为。

【问题讨论】:

  • 当有差异时,一般clang是对的,MSVS是错的,GCC会编译你扔给它的任何东西。
  • FWIW,你可以使用std::tuple_element 代替using first_type_t = typename std::tuple_element&lt;0, T&gt;::type;
  • @NathanOliver 谢谢,我完全忽略了这一点:D
  • template&lt;typename T1, typename... Ts&gt;class T 中的名称没有用处,并且在重复使用后有点误导。
  • 感谢您的参与,贾罗德。感谢您的建议,我已经相应地更新了最初的问题。

标签: c++ c++17


【解决方案1】:

暂时将您的结构声明更改为(从而摆脱不完整的类型):

template<typename>
struct first_type {};

更改您遇到的错误:

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

这为我们提供了有价值的信息:编译器选择了模板的通用版本,这意味着 Clang 不认为元组是有效的 template&lt;typename,typename...&gt;class 来实例化 first_type (这是真的 - template&lt;typename,typename...&gt;class 需要一个或更多参数,而元组也可以为空)。正如 cmets 中所指出的,这与标准本身无关,而是Clang rejects it on purpose

元组是template&lt;typename...&gt;class,所以...

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

【讨论】:

  • 我猜你现在可以在修复专业化后将主模板改回不完整的状态?
  • @TedLyngmo 这是我的回答完成还是编辑建议?
  • @303 谢谢,但它真的符合您的要求吗?我的first_type 最好命名为first_non_template_type - 如果它一直有效。我的first_type_t&lt;std::string, int&gt;std::stringfirst_type_t&lt;std::string&gt;char。 :-)
  • 如果你通过-frelaxed-template-template-args,Clang 会接受这个。由于此标志启用了默认禁用的符合标准的行为,因此 GCC 实际上是正确的。
  • @TedLyngmo 他们说这是一个突破性的变化,因为措辞有缺陷。他们似乎仍在等待修复。 ://
猜你喜欢
  • 1970-01-01
  • 2015-05-05
  • 2010-12-14
  • 1970-01-01
  • 2021-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-26
相关资源
最近更新 更多