【发布时间】:2023-03-25 22:49:02
【问题描述】:
假设一个函数模板:
template <class T>
void foo(T /* dummy */) {...}
假设foo 是这样调用的:
foo(Widget());
在这种情况下会构造一个Widget 对象吗?
This 帖子询问了一个关于未使用参数的类似问题(并且虚拟参数的参数肯定是未使用的)。答复表明,除非通过函数指针调用函数,否则编译器将优化未使用的参数。
但是,请考虑 Alexandrescu 的 Modern C++ 第 2.5 节中的以下文本:
现在假设您的应用程序中有一条规则:Widget 类型的对象是不可触及的遗留代码,并且在构造时必须采用两个参数,第二个是固定值,例如 -1。你自己的类,派生自 Widget,没有这个问题。
...
在函数没有部分特化的情况下,唯一可用的工具还是重载。一个解决方案是传递一个 T 类型的虚拟对象并依赖于重载:
template <class T, class U> T* Create(const U& arg, T /* dummy */) { return new T(arg); } template <class U> Widget* Create(const U& arg, Widget /* dummy */) { return new Widget(arg, -1); }这样的解决方案会产生构建一个未使用的任意复杂对象的开销。
这表明编译器不够聪明,无法避免为虚拟参数构造参数...
那么,哪个是正确的?如果 Alexandrescu 是正确的,那为什么不进行这种优化呢?
【问题讨论】:
-
clang 和 gcc 都觉得需要构造对象。 coliru.stacked-crooked.com/a/40a50d9448543450
-
@BaummitAugen 会是这种“感觉”背后的逻辑吗?
-
@BaummitAugen 是的,因为构造有副作用。检查这一点的唯一方法是使用无副作用的构造类和程序集。
-
解释这将是一个答案。但既然已经有了,我什至不需要尝试。 :)
-
顺便说一句,我希望他们描述
template<class T>struct tag{};,然后使用tag<Widget>和tag<T>重载作为上述问题的解决方案。不需要将类型信息作为实际实例传递。
标签: c++