c++ - 如果函数模板已经推断出返回类型,有没有办法在不实例化定义的情况下调用它?

标签 c++ templates language-lawyer

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

template <class T>
const auto& foo() { static T t; return t; }
如果 T 则定义无效应该是 void .尽管如此,我们可以单独实例化声明而不触发错误:
extern template const auto& foo<void>();  // explicit instantiation declaration
现在让我们考虑 foo 的情况。被调用,而不是被显式实例化。显然,如果 foo曾经在评估的上下文中调用,特化的定义将被实例化。在未经评估的情况下呢?我们知道,如果在未计算的上下文中调用具有非推导返回类型的函数模板,则不会实例化特化的定义。最明显的例子是 std::declval<T> .尚不清楚对于具有推导返回类型的函数是否可以这样做。
例如,我考虑过这个:
static_assert(sizeof( (void)foo<void>(), char{} ) == 1);
然而,即使在这种情况下,编译器肯定有足够的信息来评估 sizeof在不知道返回类型的情况下,仍然会出现编译错误(godbolt link)。
  • 标准的哪些规定需要实例化 foo<void> 的定义在这个情况下?
  • 有没有办法foo<void>可以在不会实例化其定义的未评估表达式中调用吗?
  • 最佳答案

    What provision of the Standard requires the instantiation of the definition of foo<void> in this situation?


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

    [...] [ Note: Therefore, any use of a specialization of the function template will cause an implicit instantiation.


    而且,[dcl.spec.auto]/14涵盖了允许显式实例化声明而不触发实例化的特殊情况,同时也暗示了为确定函数模板的返回类型而触发的实例化机制与“常规”实例化机制有些分离[]重点矿]:

    An explicit instantiation declaration does not cause the instantiation of an entity declared using a placeholder type, but it also does not prevent that entity from being instantiated as needed to determine its type. [ Example:

    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
    

     — end example ]


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

    Is there any way that foo<void> can be called inside an unevaluated expression that would not instantiate its definition?


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

    关于c++ - 如果函数模板已经推断出返回类型,有没有办法在不实例化定义的情况下调用它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64915753/

    相关文章:

    c++ - vector 的平行和

    c++ - 在 C++ 中逐字读取文件

    c++ - 模板函数的重新声明错误

    c - 在将指针转换为 `void *` 之前是否需要转换为 `uintptr_t`,反之亦然?

    c++ - stringstream 和 nullptr 的子类

    c++ - `shared_ptr` 是如何实现协变的?

    c++ - 在 Linux 上分析数据库密集型代码

    参数数量未知的 C++ 模板函数

    c++ - 错误的实例化功能本身并未实例化。 clang和gcc之间的行为差​​异

    c - C中临时对象的有效类型