【问题标题】:"Invalid use of incomplete type" using templated type and namespaces使用模板类型和命名空间的“不完整类型的无效使用”
【发布时间】:2015-08-15 03:21:52
【问题描述】:

以下是我在std::tuple 上使用的迭代器的简化版。在其中,我在一个命名空间中定义了一个模板化类型,并在第二个命名空间中使用它,如下所示:

namespace meta{
    template<size_t> struct meta_size_t {};     
}

namespace ns{

    //template<size_t> struct ns_size_t {};     

    template <size_t N> 
    void bar(meta::meta_size_t<N>) { 
        bar(meta::meta_size_t<N-1>()); 
    }
    void bar(meta::meta_size_t<1>) {}

    template<size_t N> 
    void foo() { 
        bar(meta::meta_size_t<N>()); 
    }
}

int main(void){
    ns::foo<5>();   
    return 0;
}

代码在 MSVC2015 中编译良好,但在 g++ 4.8 和 clang 3.5 (-std=c++11) 中由于达到模板的最大递归深度而失败。请注意,如果将meta::meta_size_t 替换为ns_size_t(并且ns_size_t 的定义未注释),则一切正常。

我推测编译器正在延迟 meta::meta_size_t 的解析,直到它完成解析 bar,因为它位于另一个命名空间(或类似的东西),因此失败了,但我不确定如何解决这个问题。

一般在什么情况下会出现这个问题?有没有办法强制编译器在ns's 之前解析namespace meta's 的内容?我想避免重复类型定义(以ns_size_t 为例)。

更多上下文:在原始代码中,bar 有一个std::tuple 参数,并使用std::get&lt;N&gt;(tuple) 调用重载函数

编辑: Noobish 错误。在查看了@WhozCraig 提供的示例后,我验证了可以通过交换两个bar 方法的顺序来修复代码(我假设 g++ 和 clang 按顺序搜索定义,因此永远不会注册第二个重载条,而 MSVC 必须在继续之前将所有定义添加到其符号表中)。标准是否指定了一种方法或另一种方法,或者此实现是特定的?也就是说,如果定义不在命名空间内,我不明白为什么这不是问题。

【问题讨论】:

  • 第二个bar 应该是专业吗?无论如何,您可以前向声明模板,实现重载,然后实现实际的递归模板,它应该可以编译。 See it live.
  • 你的模板递归无限的。 void bar(...&lt;N&gt;...) 需要 void bar(...&lt;N-1&gt;...),永远。
  • @WhozCraig 第二个条形图是元组迭代器的停止条件(从某种意义上说,是的,一种特殊化,但不是按照将代码裁剪为特定类型的传统意图,而只是作为一种手段控制流)
  • @DrewDormann 是,除了 bar,它不(不应该)引用 bar
  • 我知道这是停止条件。我只是期望专业化而不是超载。由于非类型模板 arg 的性质,这里不需要,但让我回过神来。

标签: c++ templates c++11 namespaces


【解决方案1】:

基本规则是,当您编写foo(/* something dependent on a template parameter*/); 时,foo 的普通非限定查找仅考虑模板定义上下文,而 ADL 将同时考虑定义和实例化上下文。因此,要考虑在模板定义上下文中找不到的重载的唯一方法是通过 ADL。

bar(meta::meta_size_t&lt;N-1&gt;());void bar(meta::meta_size_t&lt;1&gt;) {} 不在范围内,因此唯一可以调用它的方法是通过参数相关的查找,但ns 不是meta::meta_size_t&lt;1&gt; 的关联命名空间,因此您会得到无限的递归。

当你使用ns_size_t时,那么ns是一个关联的命名空间,所以bar的第二个重载被ADL找到并被重载解析选择,终止递归。

当您交换bars 的顺序时,普通的非限定查找将找到终止大小写,所以一切都很好。

MSVC 因其在模板名称查找领域的不一致性而闻名。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-28
    • 1970-01-01
    • 2017-10-24
    • 2010-10-13
    • 1970-01-01
    • 2019-12-23
    相关资源
    最近更新 更多