【问题标题】:Unexpected template instantiation when passing a pointer argument传递指针参数时出现意外的模板实例化
【发布时间】:2021-09-21 09:23:06
【问题描述】:

以下代码无法编译(在 godbolt.org 上使用 MSVC 19.28 和 /std:c++latest 和 Clang 12.0 和 -std=c++20 测试):

#include <variant>

struct some_thing;
using var = std::variant<some_thing>;

// There should be NO need to instantiate the template here, right?
void take(var* v) {}

int main() {
    var* v = nullptr;
    take(v); // This is the offending line - tries to instantiate the variant template and fails as 'some_thing' is undefined up until now.
    return 0;
}

调用 main 需要模板实例化吗?我们只是传递一个指针。这是一个错误还是我错过了什么?

Template instantiation 不应该发生在使用模板的指针类型(正如我正在做的那样)而不是当 typedef'ing 它作为 typedef 不引入新类型(即模板实例)时。我可能仍然遗漏了一些东西,但这应该使我的示例代码能够编译。

请参阅下面的 MSVC 错误消息。请注意,此问题不是关于理解错误消息的问题。它是关于为什么首先会发生模板实例化的原因。

C:/data/msvc/14.28.29333/include\type_traits(807): error C2139: 'some_thing': an undefined class is not allowed as an argument to compiler intrinsic type trait '__is_trivially_destructible'
<source>(3): note: see declaration of 'some_thing'
C:/data/msvc/14.28.29333/include\variant(956): note: see reference to class template instantiation 'std::is_trivially_destructible<some_thing>' being compiled
C:/data/msvc/14.28.29333/include\variant(956): note: see reference to variable template 'const bool conjunction_v<std::is_trivially_destructible<some_thing> >' being compiled
C:/data/msvc/14.28.29333/include\variant(1014): note: see reference to alias template instantiation 'std::_Variant_destroy_layer<some_thing>' being compiled
<source>(11): note: see reference to class template instantiation 'std::variant<some_thing>' being compiled
C:/data/msvc/14.28.29333/include\type_traits(661): error C2139: 'some_thing': an undefined class is not allowed as an argument to compiler intrinsic type trait '__is_constructible'
<source>(3): note: see declaration of 'some_thing'
C:/data/msvc/14.28.29333/include\xsmf_control.h(61): note: see reference to class template instantiation 'std::is_move_constructible<some_thing>' being compiled
C:/data/msvc/14.28.29333/include\xsmf_control.h(62): note: see reference to variable template 'const bool conjunction_v<std::is_move_constructible<some_thing>,std::negation<std::conjunction<std::is_trivially_move_constructible<some_thing> > > >' being compiled
C:/data/msvc/14.28.29333/include\xsmf_control.h(100): note: see reference to alias template instantiation 'std::_SMF_control_move<std::_Variant_destroy_layer_<some_thing>,some_thing>' being compiled
C:/data/msvc/14.28.29333/include\xsmf_control.h(139): note: see reference to alias template instantiation 'std::_SMF_control_copy_assign<std::_Variant_destroy_layer_<some_thing>,some_thing>' being compiled
C:/data/msvc/14.28.29333/include\xsmf_control.h(146): note: see reference to alias template instantiation 'std::_SMF_control_move_assign<std::_Variant_destroy_layer_<some_thing>,some_thing>' being compiled
C:/data/msvc/14.28.29333/include\variant(1014): note: see reference to alias template instantiation 'std::_SMF_control<std::_Variant_destroy_layer_<some_thing>,some_thing>' being compiled
C:/data/msvc/14.28.29333/include\type_traits(630): error C2139: 'some_thing': an undefined class is not allowed as an argument to compiler intrinsic type trait '__is_constructible'
<source>(3): note: see declaration of 'some_thing'
C:/data/msvc/14.28.29333/include\xsmf_control.h(39): note: see reference to class template instantiation 'std::is_copy_constructible<some_thing>' being compiled
C:/data/msvc/14.28.29333/include\xsmf_control.h(40): note: see reference to variable template 'const bool conjunction_v<std::is_copy_constructible<some_thing>,std::negation<std::conjunction<std::is_trivially_copy_constructible<some_thing> > > >' being compiled
C:/data/msvc/14.28.29333/include\xsmf_control.h(63): note: see reference to alias template instantiation 'std::_SMF_control_copy<std::_Variant_destroy_layer_<some_thing>,some_thing>' being compiled
C:/data/msvc/14.28.29333/include\variant(491): error C2079: 'std::_Variant_storage_<false,some_thing>::_Head' uses undefined struct 'some_thing'
C:/data/msvc/14.28.29333/include\variant(838): note: see reference to class template instantiation 'std::_Variant_storage_<false,some_thing>' being compiled
C:/data/msvc/14.28.29333/include\variant(941): note: see reference to class template instantiation 'std::_Variant_base<some_thing>' being compiled
C:/data/msvc/14.28.29333/include\xsmf_control.h(85): note: see reference to class template instantiation 'std::_Variant_destroy_layer_<some_thing>' being compiled
C:/data/msvc/14.28.29333/include\xsmf_control.h(124): note: see reference to class template instantiation 'std::_Deleted_copy_assign<std::_Variant_destroy_layer_<some_thing>,some_thing>' being compiled
C:/data/msvc/14.28.29333/include\variant(1014): note: see reference to class template instantiation 'std::_Deleted_move_assign<std::_Variant_destroy_layer_<some_thing>,some_thing>' being compiled
C:/data/msvc/14.28.29333/include\type_traits(730): error C2139: 'some_thing': an undefined class is not allowed as an argument to compiler intrinsic type trait '__is_destructible'
<source>(3): note: see declaration of 'some_thing'
C:/data/msvc/14.28.29333/include\variant(1016): note: see reference to class template instantiation 'std::is_destructible<some_thing>' being compiled
C:/data/msvc/14.28.29333/include\variant(1016): note: see reference to variable template 'const bool conjunction_v<std::is_object<some_thing>,std::negation<std::is_array<some_thing> >,std::is_destructible<some_thing> >' being compiled
C:/data/msvc/14.28.29333/include\variant(1016): error C2338: variant<Types...> requires all of the Types to meet the Cpp17Destructible requirements N4828 [variant.variant]/2.
Compiler returned: 2

【问题讨论】:

  • 很抱歉,您是否阅读了我的问题及其编辑内容?链接到的问题与我的问题并不真正相关,因为它包含 std::vector&lt;Shape&gt; shapes; 显然不会编译,因为 Shape 必须在此处实例化为它用作值(而不是作为指针,如我的问题)。
  • "转发声明std::variant"。作为未定义的行为,这是不可能的。
  • 感谢您的提示。我试图集中注意力并删除了前向声明案例。
  • 我当然从这个问题中学到了一些东西。我现在知道我上面的 cmets 大多是错误的。我删除了它们,不要混淆其他人,你可能也想清理你的 cmets

标签: c++ templates compiler-errors forward-declaration


【解决方案1】:

您的问题与ADL有关。

来自链接:

否则,对于函数调用表达式中的每个参数,都会检查其类型以确定将添加到查找中的关联的命名空间和类集。

检查将导致函数调用中使用的模板实例化,如果在这种情况下std::variant 需要some_thing 的类型定义,则会失败。

既然我们知道 ADL 是问题所在,我们可以在这种情况下简单地抑制 ADL,如果我们知道我们不想在其他命名空间或范围内查找为 @ 类型定义的函数 take() 987654325@ 使用:: operator

如果您通过将格式错误的行替换为 ::take(v); 来更改代码,您的代码将编译,因为 ADL 将不再发生。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-10
    • 2017-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-01
    • 1970-01-01
    相关资源
    最近更新 更多