【发布时间】:2023-04-04 03:32:01
【问题描述】:
考虑这个用于类型推导的伪代码:
template<typename T> void f(ParamType param);
函数调用将是:f(expr);
根据类型推导情况,ParamType 不是引用、指针,也不是通用引用 (参见 S. Meyers “Effective Modern C++”,第 14 页),但是通过值传递,以确定类型 T,首先需要 忽略'expr'的引用和常量部分,然后模式匹配exprs类型来确定T。
司机将是:
void PerformTest() {
int i = 42;
int* pI = &i;
f_const_left(pI);
f_non_template_left(pI);
f_const_right(pI);
f_non_template_right(pI);
}
现在考虑这些函数,使用这个推导规则,在以指针作为参数调用时显示出一些违反直觉的结果:
template<typename T> void f_const_left(const T t) {
// If 'expr' is 'int *' then, according to deduction rule for value parameter (Meyers p. 14),
// we need to get rid of '&' and 'const' in exp (if they exist) to determine T, thus T will be 'int *'.
// Hence, ParamType will be 'const int *'.
// From this it follows that:
// 1. This function is equivalent to function 'func(const int * t){}'
// 2. If ParamType is 'const int *' then we have non-const pointer to a const object,
// which means that we can change what pointer points to but cant change the value
// of pointer address using operator '*'
*t = 123;// compiler shows no error which is contradiction to ParamType being 'const int *'
t = nullptr; // compiler shows error that we cant assign to a variable that is const
// As we see, consequence 2. is not satisfied:
// T is straight opposite: instead of being 'const int *'
// T is 'int const *'.
// So, the question is:
// Why T is not 'const int*' if template function is f(const T t) for expr 'int *' ?
}
考虑后果 1.:
让我们创建一个等效的非模板函数:
void f_non_template_left(const int* t) {
// 1. Can we change the value through pointer?
*t = 123; // ERROR: expression must be a modifiable lvalue
// 2. Can we change what pointers points to?
t = nullptr; // NO ERROR
// As we can see, with non-template function situation is quite opposite.
}
为了实验的完整性,我们还考虑另一对函数,但从 T 的右侧放置“const”:一个模板函数及其非模板等效项:
template<typename T> void f_const_right(T const t) {
// For expr being 'int *' T will be 'int *' and ParamType will be 'int * const',
// which is definition of a constant pointer, which cant point to another address,
// but can be used to change value through '*' operator.
// Lets check it:
// Cant point to another address:
t = nullptr; // compiler shows error that we cant assign to a variable that is const
// Can be used to change its value:
*t = 123;
// So, as we see, in case of 'T const t' we get 'int * const' which is constant pointer, which
// is intuitive.
}
最后是类型右侧带有'const'的非模板函数:
void f_non_template_right(int* const t) {
// 1. Can we change the value through pointer?
*t = 123; // No errors
// 2. Can we change what pointers points to?
t = nullptr; // ERROR: you cant assign to a variable that is const
// As we can see, this non-template function is equivalent to its template prototype
}
有人能解释一下为什么模板和非模板函数之间存在这种不一致吗? 为什么左侧带有'const'的模板函数的行为不符合演绎规则?
【问题讨论】:
-
"按类型扣除" 没有类型扣除;
T和ParamType似乎不相关。 -
const T等价于std::add_const_t<T>。所以T=int*,它是int* const,而不是const int*(或int const*)。