具有类型擦除的AnyFunction类



我想实现一个类型擦除类AnyFunction,它能够存储任何带有模板化调用运算符(返回void(的实体。例如:

struct Printer {
template<typename... Args>
void operator()(Args&&... args) {
std::cout << ... << std::forward<Args>(args);
}
};
Printer typed_printer
AnyFunction printer(typed_printer);
printer(1,2.,"3");

应打印CCD_ 3。我了解如何为具有呼叫操作员已知签名的实体执行此操作。例如,这是有效的:

struct AddFunc {
void operator()(int a, int b) {
std::cout << a << "+" << b << "=" << a + b << std::endl;
}
};

struct PrintSmthFunc {
void operator()(int a, double b, const char *c) {
std::cout << a << b << c << std::endl;
}
};

int main() {
AddFunc f1;
AnyFunction addFunc(f1);
addFunc(10, 20);
PrintSmthFunc f2;
AnyFunction printSmthFunc(f2);
printSmthFunc(1, 2., "3");
}

(以下是实现:https://godbolt.org/z/r4zq6f81G)。但我不明白在模板化运算符的一般情况下如何做到这一点。。。我认为完全打字抹掉它是不可能的。

你不能完全满足你的要求。

您可以编写类型AnyPrinter,但如果不交付C++编译器并将要存储在其中的C++代码作为输入并动态编译DLL,就无法编写AnyFunction

DLL的存在应该使问题变得清楚。假设您的AnyFunction是在AnyFunction.h中定义的。

我们在DLLPrinterCode.dll中编译Printer。然后,我们在Foo.dll中编译另一种类型,称之为Foo

我们将AnyPrinter传递给AnyFunction,并从PrinterCode.dll返回它。

然后,您的可执行文件加载两个dll,将AnyFunction传递给Foo.dll,后者用私有类型Foo调用它。

知道如何打印Foo的代码住在哪里?

可执行文件无法访问Printer的源代码。CCD_ 20没有访问CCD_ 21的权限。并且CCD_ 22不能访问CCD_。

C++二进制文件不包含与您编写的代码等效的数据。它们包含该代码到标准中指定的抽象机器的投影,然后投影到机器代码。

其他语言可以实现这类功能,因为它们的运行时表示要么包括您编写的代码的所有内容,要么其通用代码不如模板强大,实际上只是自动运行时类型转换包装器。

现在,如果您想要类似Java泛型的东西,C++可以做到这一点。

您可以编写Printable,但它看起来不像C++模板代码。

struct Printer {
void operator()(std::initializer_list<PrintableRef> args) {
for(auto arg:args)
std::cout << arg;
}
};

我可以让工作。诀窍是我们在PrintableRef中进行工作。

CCD_ 26类型擦除到"0";我可以打印";。这里有一个快速的:

struct PrintableRef {
void(*print)(void*, std::ostream&) = nullptr;
void* pdata = nullptr;
template<class T> requires (!std::is_same_v<std::decay_t<T>, PrintableRef>)
PrintableRef(T&& t):
print([](void* pvoid, std::ostream& os) {
os << *static_cast<decltype(std::addressof(t))>(pvoid);
}),
pdata(std::addressof(t))
{}
PrintableRef(PrintableRef const&)=default;
~PrintableRef()=default;
PrintableRef()=delete;
friend
std::ostream& operator<<(std::ostream& os, PrintableRef self) {
self.print(self.pvoid, os);
return os;
}
};

但这还没有达到CCD_ 27的程度。

必须有人知道类型和您希望在代码中的某个时刻打印它的事实。

不幸的是,这在C++中是不可能的。一般来说,类型擦除通过运行时多态性工作,这需要虚拟函数。

使AnyFunction签名不可知的唯一方法是将其operator()作为模板。但模板不可能是虚拟的。因此,你说不可能";完全";键入擦除它。

相关内容

  • 没有找到相关文章

最新更新