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

9次阅读

共计 2214 个字符,预计需要花费 6 分钟才能阅读完成。

乍一看这个题目很玄乎,然而其实这只是波及一个很简略的 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 好~~~)

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

正文完
 0