为什么函数声明的模板参数或返回类型没有实例化?

问题描述 投票:0回答:1

我想弄清楚为什么以下代码实际上是合法的(是的,不是吗?):

template <class T>
struct Container {
    static_assert(sizeof(T) == 0); // Not triggered
    T t;
};

struct Foo;

Container<Foo> Get();
void Set(Container<Foo> v);

// Get() and Set() are NEVER defined and used

编译没有问题。 我当然知道你可以在函数声明中使用不完整的类型作为返回和参数类型。 但是,我想知道的是为什么

Container<Foo>
Get()
声明中的“
Set()
”显然不会导致
Container
模板的实例化? 特别是,实际上执行了某种模板参数一致性检查,因为例如试图返回
Container<0>
编译失败.

问题的出现是因为用不完整的类型实例化大多数标准库组件,例如

std::optional
是未定义的行为。因此:在函数声明中使用
std::optional<Foo>
和不完整的
Foo
已经是未定义的行为了吗?

在这种情况下,编译器实际上检查了模板的哪些“部分”?
什么规则管理它以及它在 C++ 标准中的何处处理?

c++ templates language-lawyer c++20 instantiation
1个回答
2
投票

但是,我想知道的是为什么 Get() 和 Set() 声明中的“容器”显然不会导致容器模板的实例化?

类模板特化只有在翻译单元中第一次使用时才隐式实例化,在需要类型完整或完整性会影响程序解释的上下文中使用。

正如你自己所说,函数声明中的类型是否完整并不重要,所以也不会有任何隐式实例化。

试图返回一个 Container<0> 编译失败。

Container<0>
本身就是错误的,只是通过
Containers
声明,不管它的定义如何。对于指定将类型作为第一个模板参数的模板,它违反了模板参数的语义要求。同样,如果例如您添加了类型约束,只要命名专业化,就会检查这些约束,而不仅仅是在实例化时。

问题的出现是因为用不完整的类型实例化大多数标准库组件(例如 std::optional)是未定义的行为。因此:在函数声明中使用 std::optional 和不完整的 Foo 是否已经是未定义的行为?

不,允许在函数声明中使用

std::optional<Foo>
作为返回类型或函数参数类型,并允许使用不完整的
Foo
。只有在函数定义中发生这种情况才会违反库要求。 (但是有一些特殊情况,例如
virtual
成员函数的协变覆盖中的返回类型必须在其声明中已经完成。)

© www.soinside.com 2019 - 2024. All rights reserved.