c++ - sizeof 运算符是否会导致模板参数推导发生?

标签 c++ templates sizeof

我知道 sizeof 运算符不会评估其表达式参数来获得答案。但它不是模板的非扣除上下文之一。所以我想知道它如何与模板交互,特别是模板参数推导。例如,以下内容摘自 C++ 模板:完整指南:

template<typename T> 
class IsClassT { 
  private: 
    typedef char One; 
    typedef struct { char a[2]; } Two; 
    template<typename C> static One test(int C::*); 
    template<typename C> static Two test(...); 
  public: 
    enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 }; 
    enum { No = !Yes }; 
};

这个类型函数 决定了,正如它的名字所暗示的,模板参数是否是一个类类型。该机制本质上是以下条件测试:

sizeof(IsClassT<T>::test<T>(0)) == 1

但是请注意,函数模板参数是显式的(在本例中为 T)并且函数参数是 int 类型的计划 0 >,它不是 指向类 C 的 int 成员的指针 类型。在正常的函数模板参数推导中,当 T 确实是类类型并且函数参数只是一个 0 时,推导 static One test(int C::* ); 应该失败,因为在模板参数推导期间不允许隐式转换(0 用作空指针类型)并且(我猜?)SFINAE 应该启动并且重载解析会被选择

static Two test(...);

但是,由于整个表达式都包含在 sizeof 运算符中,因此似乎无需强制转换即可传递 0

谁能澄清一下:

  1. 我对函数模板参数推导的理解是否正确?
  2. 是否是因为 sizeof 运算符的非求值性质使传递 0 成功?和
  3. 如果 0 在此上下文中无关紧要,我们可以选择任何参数代替 0,例如 0.0100 甚至用户定义的类型?

结论:我在C++ Primer 中找到了关于函数模板显式参数的部分。我引用“正常转换适用于明确指定的参数”和“出于同样的原因,允许对参数进行正常转换 使用普通类型定义(§ 16.2.1,第 680 页),正常转换也适用 for arguments whose template type parameter is explicitly specified”。所以这个问题中的0实际上是隐式转换为指向成员的空指针(指针转换)。

最佳答案

模板参数推导是在实例化函数时完成的。这是作为函数重载的一部分完成的(以及此处不适用的其他上下文)。在 TAD 中,函数参数的类型用于推导模板参数,但不一定使用所有参数。这就是“非推导上下文”的来源。如果模板参数出现在函数签名内的非推导上下文中,则无法从实际参数推导它。

sizeof(T)实际上是 T 的非推导上下文,但它是如此明显以至于没有人愿意提及它。例如

template< int N> class A {};
template<typename T> void f(A<sizeof(T)>);
f(A<4>());

编译器不会选择具有sizeof(T)==4 的随机T .

现在您的示例实际上没有 sizeof在函数模板的参数列表中,因此“非推导上下文”是一个无关紧要的考虑因素。也就是说,了解“sizeof 不评估其表达式参数”的含义很重要。这意味着不计算表达式 value,但计算表达式 type。在您的示例中,IsClassT<T>::test<T>(0)不会在运行时调用,但其类型在编译时确定。

关于c++ - sizeof 运算符是否会导致模板参数推导发生?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33405720/

相关文章:

c++ - 使用 x86/x64 流 SIMD 扩展的 block 匹配优化

c++ - 如何找到exe的路径

c++ - 为什么异常规范没有用?

templates - 在 Play Framework 模板中的 JavaScript 中使用花括号

c++ - C++ 的通用线程 C 包装器函数

c++ - 不同编译器中的指针大小

c++ - 为什么结构的 sizeof 不等于每个成员的 sizeof 之和?

c++ - 连接超时更短

c++ - 从包含对象访问包含对象的成员

c++ - 为什么 C++ 中空类的大小不为零?