关于javascript:C模板的非推断语境与stdtypeidentity

乍一看这个题目很玄乎,然而其实这只是波及一个很简略的CPP的模板推导的知识点。

  笔者近期进行CPP开发工作时,在编译时遇到了如下的模板类型的推断谬误:note: candidate template ignored: deduced conflicting types for parameter T (long long vs. long int)。通过一番梳理之后总结成文,心愿对大家有所帮忙。

  1.非推断语境

  家喻户晓,函数模板的应用是C++编译期进行类型推导的过程。通过剖析源代码之中函数实参的类型,进一步推断出调用的函数参数的类型,从而主动生成对应的函数,来达到精简代码逻辑的成果。

  而所谓非推断语境呢?则是模板的类型不参加模板实参推导,取而代之地应用可在别处推导或显式指定的模板实参。

  单看上述文字可能很难了解,咱们间接看代码就能明确了。

  2.举个栗子

  咱们先来看看上面的一段简略的代码:

  template<typename T>

  struct TestTemplate {

  T t;

  };

  template<typename T>

  T add(TestTemplate<T>& test, T val) {

  return test.t + val;

  }

  int main() {

  TestTemplate<long> test_template{100};

  return add(test_template, 10);

  }

  在进行编译的时候呈现如下的报错:

  note: template argument deduction/substitution failed:

  note: deduced conflicting types for parameter ‘T’ (‘long int’ and ‘int’)

  通过gcc的编译报错咱们能够看出,这里呈现了谬误的模板推断问题。模板函数add在进行类型推断时呈现了抵触,在同一个函数中,模板类型T被同时推断为long与int。

  咱们来剖析一下游戏模板推断的流程。

  首先,参数test_template的类型为TestTempalate<long>, 它作为add函数的第一个参数传入,此时T的类型被推导为了long。

  接着,参数val的类型为int, 它作为add函数的第二个参数传入,而此时因为13为int类型,所以T被推导为int类型。

  正是因为这样,在add函数进行模板推导的过程之中,两个参数test与val同时参加了模板类型的推导,导致呈现了上述的问题。

  咱们能够尝试将add函数的调用改为如下:add(test_template, 10l)。此时val也作为参数T也被推导为long类型,则编译不再报错。

  3. 利用非推断语境解决问题

  显然,下面的代码咱们心愿编译器反对将int类型主动推导为long,而不要呈现宜人的报错。那咱们就须要利用非推断语境来解决问题了,让val的类型不要参加到类型推导过程之中来,那么问题就解决了。

  模板的非推断语境呈现比较复杂,有须要的能够参考cppreference局部的具体解释。咱们将利用第一种,也是最常见的非推断语境来解决上文提到的问题。

  The nested-name-specifier (everything to the left of the scope resolution operator ::)

  简略来说就是::左侧作用域的类型,不参加模板类型的推导。

  所以上述代码改为如下代码,就能够躲避原先的问题了。

  template<typename T>

  struct TestTemplate {

  T t;

  };

  template<typename T> struct identity { typedef T type; };

  template<typename T>

  T add(TestTemplate<T>& test, typename identity<T>::type val) {

  return test.t + val;

  }

  int main() {

  TestTemplate<long> test_template{1000};

  return add(test_template, 10);

  }

  这里咱们新增加了类型identity, 并利用typename identity<T>::type躲避了模板的类型推断过程,从而让val的类型推断间接利用了test参数的类型推断后果,所以此时val的类型为long,模板类型推断也就不再出错了。

  正是因为非推断语境在模板推断中会被应用,所以C++20提供了新的trait:

  std::type_identity与std::type_identity_t来帮忙咱们解决上述的问题。它们的实现与性能与下面展现的identity统一,都是利用模板的非推断语境来躲避类型推断不同导致的编译失败问题。

  4.小结

  C++的一些模板推断的问题经常让人抓狂,很多时候gcc给出的一长串报错很容易劝退萌新。本篇聊了聊笔者理论在开发中遇到的模板推断问题登程,一步步剖析报错,心愿大家对解决编译问题有急躁,并擅用搜索引擎,功力必不唐捐。(当然,更新的C++规范也给咱们解决问题的武器库添砖加瓦,多多学习才是邪道,日常一念:C++20好~~~)

  心愿大家可能有所播种,笔者程度无限。成文之处不免有了解舛误之处,欢送大家多多探讨,指教。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理