【发布时间】:2016-07-08 22:04:20
【问题描述】:
[ EDIT ] 我将标题从works 更改为compiles,因为事实证明它根本不起作用(感谢@bogdan 的cmets)。我在帖子末尾添加了代码,说明了原因和方法。
问题的第二部分仍然存在 - 有没有办法“修复”它?问题的关键在于将基类template<int N> class X 中的虚函数Observe 重新路由到派生自X<N> 的类中的模板函数Observe<N>,而无需X 中的任何支持代码。
有关如何通过要求X 合作来完成此操作的示例,请参阅this answer 到另一个问题(基本上要求将Observe<N> 声明为最派生的类)。
在查看其他问题Choosing which base class to override method of 时,我发现以下 sn-p 在
vc++ 2015 上干净地编译(带有/W4 /Za)并返回预期的输出,但无法在gcc-5.1 和clang 3.7 上编译(尝试过在ideone.com)。
我知道模板函数的专门化有很多陷阱,但我仍然很好奇 C++ 标准的哪个字母适用于这种情况,并且 - 在代码不完全兼容的可能情况下 - 是否有一个简单的“修复”它的方法。
#include <iostream>
using std::cout;
using std::endl;
typedef int Parameter;
class Observer
{
public:
virtual void Observe(Parameter p) = 0;
};
class TaggedDispatch
{
public:
template<size_t Tag> void TObserve(Parameter p);
};
template<size_t Tag>
class TaggedObserver : virtual public TaggedDispatch, public Observer
{
public:
virtual void Observe(Parameter p) override
{ TObserve<Tag>(p); }
};
class Thing : public TaggedObserver<0>, TaggedObserver<11>
{ };
template<> void Thing::TObserve<0>(Parameter p)
{ cout << "Parent # 0, Parameter " << p << endl; }
template<> void Thing::TObserve<11>(Parameter p)
{ cout << "Parent # 11, Parameter " << p << endl; }
int main(int, char **)
{
Thing test;
test.TObserve<0>(101);
test.TObserve<11>(999);
return 0;
}
使用vc++ 2015 编译时的输出。
Parent # 0, Parameter 101
Parent # 11, Parameter 999
从gcc-5.1编译错误
prog.cpp:29:17: error: template-id 'TObserve<0>' for 'void Thing::TObserve(Parameter)' does not match any template declaration
template<> void Thing::TObserve<0>(Parameter p)
^
prog.cpp:32:17: error: template-id 'TObserve<11>' for 'void Thing::TObserve(Parameter)' does not match any template declaration
template<> void Thing::TObserve<11>(Parameter p)
从clang 3.7 编译错误。
prog.cpp:22:36: warning: 'override' keyword is a C++11 extension [-Wc++11-extensions]
virtual void Observe(Parameter p) override
^
prog.cpp:29:24: error: no function template matches function template specialization 'TObserve'
template<> void Thing::TObserve<0>(Parameter p)
^
prog.cpp:32:1: error: extraneous 'template<>' in declaration of variable 'TObserve'
template<> void Thing::TObserve<11>(Parameter p)
^~~~~~~~~~
prog.cpp:32:24: error: variable has incomplete type 'void'
template<> void Thing::TObserve<11>(Parameter p)
^
prog.cpp:32:32: error: expected ';' at end of declaration
template<> void Thing::TObserve<11>(Parameter p)
^
;
prog.cpp:32:32: error: expected unqualified-id
1 warning and 5 errors generated.
[ EDIT ] 毕竟它在
vc++ 2015 中并没有真正起作用。似乎发生的是编译器允许void Thing::TObserve<0> 定义,但在内部将其映射到void TaggedDispatch::TObserve<0>。如果添加另一个派生类,例如
class Other : public TaggedObserver<0>
{ };
template<> void Other::TObserve<0>(Parameter p)
{ cout << "Parent # 00, Parameter " << p << endl; }
然后vc++ 2015 编译失败并显示错误消息:
error C2766: explicit specialization; 'void TaggedDispatch::TObserve<0>(Parameter)' has already been defined
【问题讨论】:
-
好的,我将清理 cmets 并将信息移动到此处的答案中。这两个问题是相辅相成的,所以答案可以是一样的。
-
完成。应该报告 MSVC 中的错误。我应该这样做,还是你想自己报告?
-
@bogdan 我同意这值得报告。如果你不介意继续做。谢谢。
-
MSVC 错误reported on Connect.
-
@bogdan。谢谢。在connect 上进行了复制和投票。
标签: c++ gcc visual-c++ clang language-lawyer