[英]C++ Primer (5th ed.) : Is “16.3 Overloading and Templates” wrong in all its “more specialized” examples?
Section 16.3 of C++ Primer (5th edition) - Overloading and Templates -, teaches the function matching procedure in the presence of candidate function template(s) instantiations. C ++ Primer(第5版)的第16.3节“重载和模板”介绍了在存在候选函数模板实例化的情况下进行函数匹配的过程。
Here are the declaration for the function templates used in this section: 这是本节中使用的功能模板的声明:
using std::string;
template <class T> string debug_rep(const T &); /* 1 */
template <class T> string debug_rep(T *); /* 2 */
// definitions not relevant for the questions
string s("SO");
debug_rep(&s);
it is then said that the generated instantiations will thus be: 因此,可以说生成的实例将是:
debug_rep(const string *&)
(with T
bound to string *
) debug_rep(const string *&)
( T
绑定到string *
) debug_rep(string *)
Q1 Is it correct for #1 ? Q1对#1正确吗? Should not it instantiate
debug_rep(string* const &)
instead? 它不应该实例化
debug_rep(string* const &)
吗?
const string *sp = &s;
debug_rep(sp); //string literal type is const char[10]
it is then said that the generated instantiations will thus be: 因此,可以说生成的实例将是:
debug_rep(const string *&)
(with T
bound to const string *
) debug_rep(const string *&)
( T
绑定到const string *
) debug_rep(const string *)
Thus, both instantiated candidate would provide an exact match, selection being made on the more specialized template (-> #2) 因此,两个实例化的候选者都将提供精确匹配,在更专业的模板上进行选择(->#2)
Q2.1 Is it correct for #1 ? Q2.1对#1正确吗? Should not it instantiate
debug_rep(const string* const &)
? 它不应该实例化
debug_rep(const string* const &)
吗?
Q2.2 Assuming the instantiated function is the one just above, can we affirm it is not an exact match any more ? Q2.2假设实例化函数只是上面的函数,我们可以确定它不再是精确匹配吗?
debug_rep("SO world!"); //string literal type is const char[10]
it is then said that the generated instantiations will thus be: 因此,可以说生成的实例将是:
debug_rep(const T &)
(with T
bound to char[10]
) debug_rep(const T &)
( T
绑定到char[10]
) debug_rep(const string *)
Thus, both instantiated candidate would provide an exact match, selection being made on the more specialized template (-> #2) 因此,两个实例化的候选者都将提供精确匹配,在更专业的模板上进行选择(->#2)
Q3.1 Is the type deduced for T
correct in #1 ? Q3.1在#1中为
T
推导的类型是否正确? Should not it be const char[10]
instead ? 它不应该是
const char[10]
吗?
Q3.2 Assuming the deduced type for T
is actually the one just above, can we affirm it is not an exact match any more ? Q3.2假设
T
的推导类型实际上就是上面的推导类型,我们可以确定它不再是精确匹配吗?
You're given these declarations: 您得到以下声明:
using std::string;
template <class T> string debug_rep(const T &); /* 1 */
template <class T> string debug_rep(T *); /* 2 */
In the invocation 在调用中
string s("SO");
debug_rep(&s);
the &s
produces a string*
, which can only match the T const&
of (1) when T
is string*
. &s
产生一个string*
,仅当T
为string*
时才能与(1)的T const&
相匹配。 For the T*
in (2), there is a match for T
bound to string
. 对于(2)中的
T*
,绑定到string
T
有一个匹配项。 So, provided your quoting is correct, the book is wrong about 因此,只要您的报价是正确的,那本书就错了
debug_rep(const string *&)
being a possible instantiation: there is no such. 是一个可能的实例:没有这样的实例。
The instantiation resulting from T
= string*
would instead be 由
T
= string*
产生的实例将改为
debug_rep( string* const& )
But which instantiation will be called? 但是将调用哪个实例化?
As a general rule the simplest match is superior, but I never manage to remember the exact rules, so, I ask Visual C++ (because its typeid(T).name()
produces readable type names by default): 通常,最简单的匹配是更好的规则,但是我从来没有记住确切的规则,所以我问Visual C ++(因为默认情况下,它的
typeid(T).name()
产生可读的类型名称):
#include <iostream>
#include <string>
#include <typeinfo>
using namespace std;
template< class T >
struct Type {};
template <class T> auto debug_rep( T const& ) // 1
-> string
{ return string() + "1 --> T = " + typeid(Type<T>).name(); }
template <class T> auto debug_rep( T* ) // 2
-> string
{ return string() + "2 --> T = " + typeid(Type<T>).name(); }
auto main() -> int
{
string s( "SO" );
cout << debug_rep( &s ) << endl;
cout << "The type 'int const' is shown as " << typeid(Type<int const>).name() << endl;
}
And it says: 它说:
2 --> T = struct Type<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > The type 'int const' is shown as struct Type<int const >
And so on for your second and third examples: apparently the author got some mixup regarding const
. 对于第二个和第三个示例,依此类推:显然,作者对
const
有一些困惑。
EDIT : Thanks to Alf answer, and its elegant trick to conserve complete information about a type while using typeid
, I was able to write a program that addresses most of my questions (changing from std::string
to int
for output readability.) 编辑 :感谢Alf的回答,以及使用
typeid
可以保存有关类型的完整信息的巧妙技巧,我能够编写一个程序解决我的大多数问题(从std::string
更改为int
以提高输出可读性。)
The complete code can be edited and run rextester online IDE . 完整的代码可以编辑并运行rextester在线IDE 。
Let's define a few classes and methods: 让我们定义一些类和方法:
template <class> class Type{}; // Allowing to get full type information with typeid
template <class T> std::string typeStr()
{ return typeid(Type<T>).name(); }
template <class T> void debug_rep(const T &a) /* 1 */
{
std::cout << "[1] T type is: " << typeStr<T>()
<< "\t| arg type is: " << typeStr<decltype(a)>() << std::endl;
}
template <class T> void force_1(const T &a) /* 1 */
{
std::cout << "[forced 1] T type is: " << typeStr<T>()
<< "\t| arg type is: " << typeStr<decltype(a)>() << std::endl;
}
template <class T> void debug_rep(T *a) /* 2 */
{
std::cout << "[2] T type is: " << typeStr<T>()
<< "\t| arg type is: " << typeStr<decltype(a)>() << std::endl;
}
Running: 运行:
std::cout << "---First example---" << std::endl;
int i = 41;
debug_rep(&i);
force_1(&i);
Displays: 显示:
---First example---
[2] T type is: class Type<int> | arg type is: class Type<int *>
[forced 1] T type is: class Type<int *> | arg type is: class Type<int * const &>
Q1 : we can remark that, when we call force_1, instantiating a template corresponding to #1, the argument type is int * const &
, so the book is not correct, and the instantiated candidate #1 would be 问题1 :我们可以说,当我们调用force_1时,实例化与#1对应的模板时,参数类型为
int * const &
,因此书不正确,实例化的候选#1将为
debug_rep(int* const &)
Running: 运行:
std::cout << "---Second example---" << std::endl;
const int *ip = &i;
debug_rep(ip);
force_1(ip);
Displays: 显示:
---Second example---
[2] T type is: class Type<int const > | arg type is: class Type<int const *>
[forced 1] T type is: class Type<int const *> | arg type is: class Type<int const * const &>
Q2.1 : Calling force_1
, we remark that the argument type will be int const * const &
, so the book is missing const qualification on the reference. Q2.1 :调用
force_1
,我们注意到参数类型为int const * const &
,因此这本书在参考文献上缺少const限定符。 The instantiated candidate will actually be: 实例化的候选人实际上将是:
debug_rep(const int * const &)
Q2.2 The second candidate being debug_rep(const int *)
, it is an exact match for ip
(which is a pointer to constant integer). Q2.2第二个候选对象是
debug_rep(const int *)
,它与ip
(这是指向常量整数的指针)完全匹配。 To check if the first candidate has a lower rank, let's write: 要检查第一个候选人的排名是否较低,让我们写:
void debug_rep_plain_b(const int * const &) /* 1 */
{ std::cout << "[plain 1]" << std::endl;}
void debug_rep_plain_b(const int *) /* 2 */
{ std::cout << "[plain 2]" << std::endl; }
If we try to compile: 如果我们尝试编译:
debug_rep_plain_b(ip)
There is a compilation error for ambiguous call: So the answer to Q2.2 is NO, it is still an exact match ! 模棱两可的调用存在编译错误:因此,对Q2.2的回答为“否”,它仍然是完全匹配的! For the templated version, the compiler actually uses the rule regarding the most specialized template to resolve the ambiguity.
对于模板版本,编译器实际上使用有关最专业模板的规则来解决歧义。
Even if there is a mistake in the deduced candidate, the book is correct regarding the fact that this example illustrates overload resolution using the most specialized template. 即使推断出的候选者有误,该书也正确无误,因为该示例使用最专业的模板说明了重载解决方案。
Running: 运行:
std::cout << "---Third example---" << std::endl;
const int ia[3] = {1, 2, 3};
debug_rep(ia);
force_1(ia);
Displays: 显示:
---Third example---
[2] T type is: class Type<int const > | arg type is: class Type<int const *>
[forced 1] T type is: class Type<int const [3]> | arg type is: class Type<int const (&)[3]>
Q3.1 The type deduced for T
by CL is array of const integer, so the book would be mistaken. Q3.1 CL为
T
推导的类型是const整数数组,因此会被误认为是本书。
BUT the result is inconsistent with GCC or Clang, that would output: 但是结果与GCC或Clang不一致,将输出:
---Third example---
[2] T type is:4TypeIKiE | arg type is: 4TypeIPKiE
[forced 1] T type is:4TypeIA3_iE | arg type is: 4TypeIRA3_KiE
The interesting part being: 有趣的部分是:
[forced 1] T type is:4TypeI A3_i E [强制1] T类型为:4TypeI A3_i E
meaning that they deduce T
as an array of 3 non -const integers (because _i, not _Ki), which would agree with the book. 表示他们将
T
推导为3个非常量整数的数组(因为_i而不是_Ki),这与本书一致。
I will have to open another question for this one, I cannot understand the type deduction operated by GCC and Clang... 我将不得不为此提出另一个问题,我无法理解GCC和Clang进行的类型推导...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.