C++ 未编译函数模板中使用的类的正向声明
下面的代码不是用gcc编译的,而是用MSVC编译的C++ 未编译函数模板中使用的类的正向声明,c++,templates,gcc,forward-declaration,C++,Templates,Gcc,Forward Declaration,下面的代码不是用gcc编译的,而是用MSVC编译的 class B; class A { B *_parent; public: template <typename T> void Do(T val) { _parent->DoB(val); } A(B *parent) : _parent(parent) { } }; class B : public A { pu
class B;
class A
{
B *_parent;
public:
template <typename T>
void Do(T val)
{
_parent->DoB(val);
}
A(B *parent)
: _parent(parent)
{
}
};
class B : public A
{
public:
B()
: A(nullptr)
{
}
void DoB(int val)
{
cout << val << endl;
}
};
int main() {
B b;
A a(&b);
a.Do(10);
return 0;
}
根据类似帖子,根据本标准第14.6.9段,gcc的行为是正确的。但这是违反直觉的,因为模板应该只在使用的地方实例化。唯一的用法是在定义了所有类之后
我的问题是这个问题的解决办法是什么?因为在这种情况下使用成员模板非常方便。可能是架构或其他方面的问题?您可以声明依赖于
B
的A
部分是已知的,但稍后再定义它们。声明如下所示
class B;
class A
{
B *_parent;
public:
template <typename T> void Do(T val); /* (see below) */
A(B *parent) : _parent(parent) {}
};
最后定义缺失的部分
template <typename T> void A::Do(T val)
{
_parent->DoB(val); /* Fine, B is known. */
}
模板无效A::Do(T val)
{
_父->DoB(val);/*很好,B是已知的*/
}
作为补充说明,使用gcc 8编译的原始代码仅包含一个警告。您可以添加额外的层:
class A
{
B *_parent;
private:
template <typename TB, typename T>
static void CallDoB(TB* b, T&& val) {
b->DoB(std::forward<T>(val));
}
public:
template <typename T>
void Do(T val)
{
CallDoB(_parent, val);
}
A(B *parent) : _parent(parent) {}
};
A类
{
B*父母;
私人:
模板
静态无效CallDoB(TB*b、T和val){
b->DoB(标准:正向(val));
}
公众:
模板
无效Do(T val)
{
CallDoB(_parent,val);
}
A(B*家长):_家长(家长){}
};
现在
b->
依赖于模板,并被推迟到真正的实例化。设计肯定很奇怪。也许你会想使用?14.6.9的什么版本的标准?在任何情况下,是的,模板定义中任何不“依赖”模板参数的内容都必须在模板定义中格式良好,即使从未实例化,这里的\u parent->DoB
子表达式违反了该规则。在本例中,我修复了标题中的术语,因为,实际上,我已经提出了一个类似的解决方案:template void Do(T val){static_cast(this)->\u parent->DoB(val);}
template <typename T> void A::Do(T val)
{
_parent->DoB(val); /* Fine, B is known. */
}
class A
{
B *_parent;
private:
template <typename TB, typename T>
static void CallDoB(TB* b, T&& val) {
b->DoB(std::forward<T>(val));
}
public:
template <typename T>
void Do(T val)
{
CallDoB(_parent, val);
}
A(B *parent) : _parent(parent) {}
};