【问题标题】:If a function template has deduced return type, is there a way to call it without instantiating the definition?如果函数模板已经推断出返回类型,有没有办法在不实例化定义的情况下调用它?
【发布时间】:2020-11-19 16:21:14
【问题描述】:

考虑一些函数模板,例如:

template <class T>
const auto& foo() { static T t; return t; }

如果Tvoid,则该定义无效。尽管如此,我们还是可以单独实例化声明而不触发错误:

extern template const auto& foo<void>();  // explicit instantiation declaration

现在让我们考虑调用foo 而不是显式实例化的情况。显然,如果 foo 曾经在评估的上下文中被调用,则将实例化特化的定义。在未经评估的情况下呢?我们知道,如果在未计算的上下文中调用具有非推导返回类型的函数模板,则不会实例化特化的定义。最明显的例子是std::declval&lt;T&gt;。尚不清楚对于具有推导返回类型的函数是否可以这样做。

例如,我考虑过这个:

static_assert(sizeof( (void)foo<void>(), char{} ) == 1);

但是,即使在这种情况下,编译器肯定有足够的信息来评估 sizeof 表达式而不知道返回类型,仍然会发生编译错误 (godbolt link)。

  • 标准的哪些规定要求在这种情况下实例化foo&lt;void&gt; 的定义?
  • 有什么方法可以在不会实例化其定义的未计算表达式中调用foo&lt;void&gt;

【问题讨论】:

  • 标准的哪些规定要求在这种情况下实例化 foo 的定义?标准仅在获取函数timsong-cpp.github.io/cppwp/n4659/temp.deduct.funcaddr#2 的地址时才要求: /
  • 我问a related question,类模板的非模板成员函数的特化的显式实例化声明似乎会导致相关类模板特化的实例化(根据 GCC/Clang)。推导出成员函数的返回类型可能与我的问题无关,但我主要使用它来获得 [dcl.spec.auto]/14 的支持,即显式实例化声明不应导致实例化。
  • 我们知道,如果在未计算的上下文中调用具有非推导返回类型的函数模板,则特化的定义不会被实例化我认为是CWG1378.

标签: c++ templates language-lawyer


【解决方案1】:

标准的哪些规定要求在这种情况下实例化foo&lt;void&gt; 的定义?

尽管是非规范性的,[dcl.spec.auto]/11 中的注释确实提到 任何 使用专门化(在其声明的返回类型中具有占位符的函数模板)将导致隐式实例化 [extract ,强调我的]:

[...] [ 注意:因此,对函数模板的任何特化的使用都会导致隐式实例化。

此外,[dcl.spec.auto]/14 涵盖了允许显式实例化声明而不触发实例化的特殊情况,同时也可以说暗示为确定函数模板的返回类型而触发的实例化机制在某种程度上与“常规" 实例化机制 [强调 我的]:

显式实例化声明不会导致使用占位符类型声明的实体实例化,但它也不会阻止根据需要实例化该实体以确定其类型。 [ 示例:

template <typename T> auto f(T t) { return t; }
extern template auto f(int);    // does not instantiate f<int>
int (*p)(int) = f;              // instantiates f<int> to determine its return type, but an explicit
                                // instantiation definition is still required somewhere in the program

 — 结束示例 ]

示例的注释(非规范性)指出,这种特殊情况触发的隐式实例化仅用于返回类型推导,并且不放弃在其他地方对显式实例化定义的需要。


有什么方法可以在不会实例化其定义的未计算表达式中调用foo&lt;void&gt;

鉴于上述讨论,我会说:不。即使在未评估的表达式中调用也属于(非规范)“任何使用”。

【讨论】:

    猜你喜欢
    • 2021-12-26
    • 1970-01-01
    • 1970-01-01
    • 2010-11-03
    • 2011-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-21
    相关资源
    最近更新 更多