2 回答
TA贡献1883条经验 获得超3个赞
的直接背景基本上是什么,你在模板声明本身看到的。除此之外的一切都是硬错误。硬错误示例:
#include <type_traits>template<class T>struct trait{ using type = typename T::type; };template<class T, class U = typename trait<T>::type>void f(int);void f(...);template<class T, class U = typename T::type>void g(int);void g(...);template<class>struct dependent_false : std::false_type{};template<class T>struct X{ static_assert(dependent_false<T>(), "..."); using type = void;};int main(){ f<int>(0); g<X<int>>(0);}
TA贡献1799条经验 获得超6个赞
如果您考虑了确定模板参数替换结果所需的所有模板和隐式定义的函数,并假设它们是在替换开始之前首先生成的,则在第一步中发生的任何错误都不会立即出现,并导致硬错误。
如果所有这些实例化和隐式定义(可能包括将函数定义为已删除)都可以正确执行,那么替换期间(即在引用函数模板的实例化模板和隐式定义函数时)会发生任何其他“错误”。签名)不是错误,但会导致推理失败。
因此,给定这样的功能模板:
template<typename T>voidfunc(typename T::type* arg);
以及在其他功能的推论失败时将使用的“后备”:
template<typename>voidfunc(...);
和这样的类模板:
template<typename T> struct A { typedef T* type; };
调用func<A<int&>>(nullptr)
将替代A<int&>
,T
并且为了检查是否T::type
存在,必须实例化A<int&>
。如果我们设想在调用之前放一个显式实例化func<A<int&>(nullptr)
:
template class A<int&>;
那么这将失败,因为它尝试创建类型int&*
并且不允许使用指向引用的指针。我们没有到检查替换是否成功的地步,因为实例化存在一个严重的错误A<int&>
。
现在,我们有一个明确的专业化A
:
template<> struct A<char> { };
对的调用func<A<char>>(nullptr)
需要实例化A<char>
,因此请想象在调用之前程序中某个地方的显式实例化:
template class A<char>;
此实例化还可以,没有任何错误,因此我们继续进行参数替换。work的实例化A<char>
,但A<char>::type
不存在,但是可以,因为它仅在的声明中引用func
,因此只会导致参数推导失败,而...
将调用后备功能。
在其他情况下,替换可能导致特殊成员函数被隐式定义(可能已删除),这可能会触发其他实例化或隐式定义。如果在“生成实例和隐式定义”阶段发生错误,那么它们就是错误,但是如果成功但在替换期间发生错误,则函数模板签名中的表达式将变为无效,例如,因为它使用的成员不存在或被隐式定义为删除的东西,这不是错误,只是推论失败。
因此,我使用的思维模型是,替换需要首先执行“准备”步骤才能生成类型和成员,这可能会导致严重错误,但是一旦我们完成了所有必要的生成,任何进一步的无效使用就不会出错。当然,这一切都是将问题从“ 即时上下文是什么意思?” 移开。“在检查此替换之前需要生成哪些类型和成员?” 因此它可能会或可能不会帮助您!
- 2 回答
- 0 关注
- 630 浏览
添加回答
举报