专业 C++从未调用过模板方法
还有另一个模板专业化问题,我无法解决:
terminallog.hhterminallog.hh
//stripped code
class Terminallog {
public:
Terminallog();
Terminallog(int);
virtual ~Terminallog();
template <class T>
Terminallog & operator<<(const T &v);
template <class T>
Terminallog & operator<<(const std::vector<T> &v);
template <class T>
Terminallog & operator<<(const T v[]);
Terminallog & operator<<(const char v[]);
//stripped code
};
继续(感谢评论进行编辑)
//stripped code
template <class T>
Terminallog &Terminallog::operator<<(const T &v) {
std::cout << std::endl;
this->indent();
std::cout << v;
return *this;
}
template <class T>
Terminallog &Terminallog::operator<<(const std::vector<T> &v) {
for (unsigned int i = 0; i < v.size(); i++) {
std::cout << std::endl;
this->indent();
std::cout << "Element " << i << ": " << v.at(i);
}
return *this;
}
template <class T>
Terminallog &Terminallog::operator<<(const T v[]) {
unsigned int elements = sizeof (v) / sizeof (v[0]);
for (unsigned int i = 0; i < elements; i++) {
std::cout << std::endl;
this->indent();
std::cout << "Element " << i << ": " << v[i];
}
return *this;
}
inline
Terminallog &Terminallog::operator<<(const char v[]) {
std::cout << std::endl;
this->indent();
std::cout << v;
return *this;
}
//stripped code
这编译得很好,没有错误。但是,当我尝试执行以下操作时:
Terminallog clog(3);
int test[] = {5,6,7,8};
clog << test;
它总是向我打印数组的指针地址。换句话说,专用模板
Terminallog & operator<<(const T v[]);
永远不会被调用。我还通过额外的 cout 验证了这一点。无论我尝试什么,程序总是在调用
Terminallog & operator<<(const T &v);
而不是专业化。显然我的代码中一定有错误,但我找不到它。
And another template specialization problem, which I can't resolve:
terminallog.hh
//stripped code
class Terminallog {
public:
Terminallog();
Terminallog(int);
virtual ~Terminallog();
template <class T>
Terminallog & operator<<(const T &v);
template <class T>
Terminallog & operator<<(const std::vector<T> &v);
template <class T>
Terminallog & operator<<(const T v[]);
Terminallog & operator<<(const char v[]);
//stripped code
};
terminallog.hh continued (edited thanks to comment)
//stripped code
template <class T>
Terminallog &Terminallog::operator<<(const T &v) {
std::cout << std::endl;
this->indent();
std::cout << v;
return *this;
}
template <class T>
Terminallog &Terminallog::operator<<(const std::vector<T> &v) {
for (unsigned int i = 0; i < v.size(); i++) {
std::cout << std::endl;
this->indent();
std::cout << "Element " << i << ": " << v.at(i);
}
return *this;
}
template <class T>
Terminallog &Terminallog::operator<<(const T v[]) {
unsigned int elements = sizeof (v) / sizeof (v[0]);
for (unsigned int i = 0; i < elements; i++) {
std::cout << std::endl;
this->indent();
std::cout << "Element " << i << ": " << v[i];
}
return *this;
}
inline
Terminallog &Terminallog::operator<<(const char v[]) {
std::cout << std::endl;
this->indent();
std::cout << v;
return *this;
}
//stripped code
This compiles just fine, no errors. However when I try to do something like:
Terminallog clog(3);
int test[] = {5,6,7,8};
clog << test;
it always prints me the pointer-address the of the array. In other words the specialized template
Terminallog & operator<<(const T v[]);
is never called. I also verified this with an additional cout. No matter what I try the program is always calling
Terminallog & operator<<(const T &v);
and not the specialization. Obviously there has to be an error in my code, however I can't find it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
我敢打赌,这里应用了转换规则。由于
int [5]
(这是数组的实际类型)没有完全匹配,因此您的数组将衰减为int*
以及的重载const T&
将被选择,因为它将比const T v[]
(被视为const T* v
)更好的匹配。有关这种情况下重载解析机制的详细说明,请参阅 @sth 的答案。
如果你尝试:
相反,会怎样?
顺便说一句,
T[]
重载定义中的sizeof
内容是完全错误的。您无法通过这种方式获得尺寸。同样,数组将衰减为指针,并且元素
将始终为sizeof(T*) / sizeof(T)
。My bet is that conversion rules are applied here. Since there is no exact match for
int [5]
(which is the actual type of your array), your array will decay toint*
and the overload withconst T&
will be chosen, since it will be a better match thanconst T v[]
(which is treated asconst T* v
).See @sth 's answer for a detailed explanation on the overload resolution mechanism in this case.
What if you try:
instead ?
By the way the
sizeof
stuff in the definition of the overload withT[]
is plain wrong. You cannot get the size this way. Again the array will decay to a pointer andelements
will always besizeof(T*) / sizeof(T)
.在您的代码中,您定义了几个重载函数模板(它们不是某些通用模板的特化,它们是单独的重载。但这没有任何问题,没有理由它们必须是特化的。)
其中一个模板具有
const T v[]
的参数声明。由于数组不能按值传递,因此编译器的解释方式与声明参数const T *v
相同。对于问题中的数组(最终为 int[5] 类型),编译器必须在两个匹配模板之间进行选择。根据标准中的 §13.3.3.1.1(表 10),最佳匹配由所需转换的数量和类型决定。
const T&
模板与T = int[5]
匹配。根据 §13.3.3.1.4/2,将int[5]
转换为 constint(&)[5]
参数需要与转换 < code>int[5] 到 constint[5]
。这是一次限定转换(添加const
)。const T*
模板与T = int
匹配。将int[5]
转换为const int*
需要两次转换。首先是数组到指针的转换(int[5]
到int*
),然后是限定转换(int*
到常量 int*
)。所有这些转换都符合“完全匹配”的条件,但由于第二个模板需要两次此类转换,而第一个模板只需要一个,因此第一个模板是更好的匹配。
要获得“正确”匹配,您可以从第二个模板的参数中删除 const,或者为仅调用 const 版本的非 const 指针添加一个附加模板:
话虽如此,请注意,您无法在这样的函数中使用
sizeof
获取数组长度。具有附加尺寸参数的模板(如 Alexandre C. 在他的回答中建议的那样)可能是更好的选择。In your code, you define several overloaded function templates (They are not specializations of some generic template, they are separate overloads. But there is nothing wrong with that, there is no reason they would have to be specializations.)
One of these templates has a parameter declaration of
const T v[]
. Since arrays cannot be passed by value, this is interpreted by the compiler just the same as if the parameter was declaredconst T *v
.For the array in questions, which ends up to be of type
int[5]
, the compiler has to chose between two matching templates. The best match is determined by the number and type of conversions needed, according to §13.3.3.1.1 (Table 10) in the standard.const T&
template matches forT = int[5]
. According to §13.3.3.1.4/2 converting theint[5]
to a constint(&)[5]
parameter requires the same conversions as converting anint[5]
to a constint[5]
. This is one qualification conversion (adding aconst
).const T*
template matches forT = int
. Converting aint[5]
to aconst int*
requires two conversions. First and array-to-pointer conversion (int[5]
toint*
), then a qualification conversion (int*
toconst int*
).All these conversions qualify as "exact matches", but since the second template would require two such conversions while the first template requires only one, the first template is a better match.
To get the "correct" match, you could remove the
const
from the parameter of the second template, or add an additional template for non-const pointers that just calls the const version:All that being said, note that you cannot get the array length with
sizeof
in a function like this. A template with an additional size parameter like suggested by Alexandre C. in his answer might be a better choice for that.首先,这里没有专业化,而是重载函数。
然后,我假设问题如下:
所以现在在重载解析期间编译器选择
第一个是完全匹配的,所以它“获胜”。
First of all, you don't have specializations here, but overloaded functions.
Then, I assume the problem is as follows:
So now during overloading resolution compiler chooses between
First one is exact match, so it "wins".
首先:不存在 extern 模板之类的东西(C++ 标准中有导出关键字,但它被 MS 和 GNU 等主要编译器生产商忽略,现在似乎已被放弃)。所以你必须将模板函数体放在头文件中。
第二:最好忘记部分模板专业化。它的支持不够好,例如,MS 仅对部分类模板专门化提供非常有限的支持(对于指针、引用、指向成员的指针和函数指针(看这里))。所以最好不要使用它。但您可以使用完全显式的模板专业化。
第三:您的代码中实际上没有任何模板专业化,
它们是三个不同的函数模板,并且
只是函数。
函数模板专业化的正确语法是这样的
但这不是重点。根据标准中定义的规则,重载解析仍必须导致最专门的函数或函数模板(如果不存在此类函数)。但我不确定是否存在完全兼容的 C++ 实现(除了由无人使用的标准作者开发的 Comeau C++ 之外)。我认为,如果您有两个完全匹配的重载或没有一个重载(并且需要隐式转换),您可能会遇到不合规问题。
另请注意:
仅在命名空间范围内允许函数模板特化。这意味着您不能声明成员函数模板特化。但当然,您可以像以前一样定义重载。
First: there is no such thing as extern templates (there was export keyword in C++ standard but it was ignored by major compiler producers like MS and GNU and now seems abandoned). So you have to put template function bodies in header file.
Second: better forget partial template specialization. It is not supported well enough, e.g. MS provides only very limited support for partial class template specialization (for pointers, references, pointer to member and function pointers (Look here)). So better just don't use it. But you can use fully explicit template specialization.
Third: you don't really have any template specializations in your code
are three distinct function templates and
is just function.
The right syntax for function template specializations is this
But it is not really the point. The overloading resolution must still lead to the most specialized function or function template (if no such function exist) according to the rules defined in the standard. But I'm not sure that fully compliant C++ implementation exist (except Comeau C++ developed by standard authors used by nobody). I think that if you have two overloads that match exactly or none of them (and implicit conversion is required) you may have problems with non-compliance.
ALSO NOTE:
Function template specializations are allowed in namespace scope only. It means that you may not declare member function template specializations. But of course you may define overloads like you did.
首先,您没有进行模板专业化:
是两个不同的函数。
如果您尝试定义一个。正如 ssteinberg 指出的那样,为了表明您正在专门化模板,您需要使用T
类型为char
的输出,那么您的编译器应该会抱怨有歧义template<>
表示法。然而,在这种情况下,这可能不会对您有帮助,因为我不相信您可以专门化成员函数(如果它们是静态的,也许您可以?)。因此,如果您尝试遵循 ssteinberg 的建议,您的编译器将会抱怨。您需要模板化整个类,然后专门化各个函数。
以下链接可能会提供一些帮助,http://womble .decadent.org.uk/c++/template-faq.html#mem-fun-specialization
编辑:
以下内容可能是说明性的:
输出是
First of all you are not doing template specialization:
are two different functions.
If you tried to define an output where. To indicate that you are specializing a template, as ssteinberg notes, you need to use theT
is of typechar
then your compiler should complain of an ambiguitytemplate<>
notation.In this case, however, this probably won't help you as I don't believe you can specialize member functions (maybe you can if they are static?). So your compiler will complain if you try to follow ssteinberg's advice. You need to template the whole class, and then specialize individual functions.
The following link might provide some help, http://womble.decadent.org.uk/c++/template-faq.html#mem-fun-specialisation
EDIT:
The following might be illustrative:
Output is
尝试将
template<>
放在Terminallog & 前面。 operator<<(const char v[]);
告诉编译器您正在专门化一个模板。Try to put
template<>
in front ofTerminallog & operator<<(const char v[]);
to tell the compiler that you're specializing a template.显式专用模板实例化:
类似这样的东西。我的 C++ 生锈了。
Explicit specialized template instantiation:
Something like this. My C++ is rusty.