如何在类模板中延迟对虚拟函数的调用?
请看下面的代码:
template <typename T>
int badToCall() = delete;
struct IA {
virtual ~IA() {}
virtual int foo() const = 0;
};
template <typename T>
struct A : public IA {
virtual int foo() const override final { return badToCall<T>(); }
};
int main() { A<int> a; }
如何延迟对A<int>::foo的求值/实例化,以便我可以在这里实例化A<int>而不触发一个 "call to deleted function" 错误?
我在网上找到了类似的问题,其中有几个提到在实例化A时必须构造A的vtable,从而触发对A::foo 的急切求值。但在我看来,那只需要对A::foo进行声明,而不需要实际定义,类似于普通的非模板虚函数声明。因此,我觉得似乎有可能延迟对完整求值。
编辑:如果我不使用模板,我可以这样为int编写实现:
AInt.h
struct AInt: public IA {
virtual int foo() const override final;
}
实现可以放在cpp中,与模板特化一起:
AInt.cpp
template<>
int badToCall<int>() {
return 1;
}
int AInt::foo() {
return badToCall<int>();
}
这个结构体在仅包含AInt.h时仍然可以被实例化;如下所示:
#include "AInt.h"
int main() {
AInt a;
}
我想实现同样的效果,但不想手动提供一个 AInt 结构体,因此我希望能够这样做
int main() {
A<int> a;
}
因此我想延迟定义 A<X>::foo,最好不需要列出显式的实例化。我猜我希望那些不使用 A<X>::foo 的编译单元不为它输出任何代码,而使用它的编译单元输出代码,并进行去重。
解决方案
将代码在头文件和.cpp/.inl之间尽量按常规代码分开。
不要在头文件中提供 A<T>::foo 的实现,而只在需要的地方提供
在A.hpp:
struct IA {
virtual ~IA() {}
virtual int foo() const = 0;
};
template <typename T>
struct A : public IA {
virtual int foo() const override final;
};
在main.cpp
#include <A.hpp>
int main() { A<int> a; }
并且在Serialize.cpp中,大致如下:
#include <A.hpp>
template <typename T>
int badToCall() = delete;
// All specialization of `badToCall` for specific type.
template <>
int badToCall<A>() { return 42; }
template <typename T>
int A::foo() const { return badToCall<T>(); }
void Serialize(const A<int>& a)
{
a.foo();
}
我会用重载来替代对specialization的使用
在A.inl / A.hxx或者关于内联实现的任何约定
#include <A.hpp>
struct ADL_enabler {}; // Needed mostly for built-in types.
template <typename T>
int A::foo() const { return foo_impl(std::type_identity<T>, ADL_enabler{}); }
// Each usage of `A::foo` should see declaration of matching overload `foo_impl`
以及在SerializeInt.cpp:
#include <A.hpp>
#include <A.inl>
int foo_impl(std::type_identity<int>, ADL_enabler) { return 42; }
void Serialize(const A<int>& a)
{
a.foo();
}
以及在SerializeDouble.cpp:
#include <A.hpp>
#include <A.inl>
int foo_impl(std::type_identity<double>, ADL_enabler) { return 51; }
void Serialize(const A<double>& a)
{
a.foo();
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。