我知道 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
。
谁能澄清一下:
- 我对函数模板参数推导的理解是否正确?
- 是否是因为
sizeof
运算符的非求值性质使传递0
成功?和 - 如果
0
在此上下文中无关紧要,我们可以选择任何参数代替0
,例如0.0
、100
甚至用户定义的类型?
结论:我在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/