类中不允许使用不完整的类型,但类模板中允许使用不完整的类型 [英] Incomplete type is not allowed in a class, but is allowed in a class template

查看:656
本文介绍了类中不允许使用不完整的类型,但类模板中允许使用不完整的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是无效的代码:

struct foo {
    struct bar;
    bar x;        // error: field x has incomplete type
    struct bar{ int value{42}; };
};

int main() { return foo{}.x.value; }

这很清楚,因为foo::bar在定义foo::x时被认为是不完整的.

This is quite clear, as foo::bar is considered incomplete at the point where foo::x is defined.

但是,似乎有一个解决方法"使相同的类定义有效:

However, there seems to be a "workaround" which makes the same class definition valid:

template <typename = void>
struct foo_impl {
    struct bar;
    bar x;        // no problems here
    struct bar{ int value{42}; };
};

using foo = foo_impl<>;

int main() { return foo{}.x.value; }

适用于所有主要编译器. 我对此有三个问题:

This works with all major compilers. I have three questions about this:

  1. 这确实是有效的C ++代码,还是只是一些古怪的编译器?
  2. 如果它是有效的代码,那么C ++标准中是否有一个段落处理此异常?
  3. 如果它是有效的代码,为什么第一个版本(不带template)被视为无效?如果编译器可以找出第二个选项,那么我看不出为什么它不能找出第一个选项的原因.
  1. Is this indeed valid C++ code, or just a quirk of the compilers?
  2. If it is valid code, is there a paragraph in the C++ standard that deals with this exception?
  3. If it is valid code, why is the first version (without template) considered invalid? If the compiler can figure out the second option, I don't see a reason why it wouldn't be able to figure out the first one.


如果我为void添加了显式的专业化:


If I add an explicit specialization for void:

template <typename = void>
struct foo_impl {};

template<>
struct foo_impl<void> {
    struct bar;
    bar x;        // error: field has incomplete type
    struct bar{ int value{42}; };
};

using foo = foo_impl<>;

int main() { return foo{}.x.value; } 

它再次无法编译.

推荐答案

真正的答案可能是\\ _(ツ)_/¯,但由于模板具有魔力,目前可能还可以,但是更明确地说,它不可以等待其他一些核心问题解决方案.

The real answer might be ¯\_(ツ)_/¯, but it's probably currently okay because templates are magical, but it may be more explicitly not okay pending some other core issue resolutions.

首先,当然主要的问题是 [class.mem]/14 :

First, the main problem of course is [class.mem]/14:

非静态数据成员不应具有不完整的类型.

Non-static data members shall not have incomplete types.

这就是为什么您的非模板示例格式错误的原因.但是,根据 [temp.point]/4 :

This is why your non-template example is ill-formed. However, according to [temp.point]/4:

对于类模板专业化,类成员模板专业化或类模板的类成员的专业化,如果该专业化是隐式实例化的,因为该专业化是从另一个模板专业化内部引用的,则如果该专业化所源自的上下文引用的引用取决于模板参数,并且如果未在封闭模板的实例化之前实例化专业化,则实例化点紧接在封闭模板的实例化点之前.否则,这种专门化的实例化点紧接在引用该专门化的名称空间范围声明或定义之前.

For a class template specialization, a class member template specialization, or a specialization for a class member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization, if the context from which the specialization is referenced depends on a template parameter, and if the specialization is not instantiated previous to the instantiation of the enclosing template, the point of instantiation is immediately before the point of instantiation of the enclosing template. Otherwise, the point of instantiation for such a specialization immediately precedes the namespace scope declaration or definition that refers to the specialization.

这建议foo_impl<void>::bar之前 foo_impl<void>实例化,因此在实例化bar类型的非静态数据成员的位置完成.所以也许没关系.

Which suggests that foo_impl<void>::bar is instantiated before foo_impl<void>, and hence it's complete at the point where the non-static data member of type bar is instantiated. So maybe it's okay.

但是,核心语言问题 2335 处理关于完整性和模板的不完全相同但仍然非常相似的问题,并且两者都指向希望使模板用例与非模板用例更加一致.

However, core language issues 1626 and 2335 deal with not-exactly-the-same-but-still-quite-similar issues regarding completeness and templates, and both point to desiring to make the template case more consistent with the non-template case.

从整体上看,这一切意味着什么?我不知道.

What does all of this mean when viewed as a whole? I'm not sure.

这篇关于类中不允许使用不完整的类型,但类模板中允许使用不完整的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆