【问题标题】:Calling method with incomplete return type and my unexplainable template-workaround返回类型不完整的调用方法和我无法解释的模板解决方法
【发布时间】:2015-08-05 12:22:30
【问题描述】:

为了解释我的情况,我必须发布相当多的代码。但是,问题很简单(另请参阅我的帖子的最底部和最后一个代码段):

SubscriptProxy::is中,为什么调用this->get_element<Something>(parentElement);时可以编译,而调用XYZ::get_element<Something>(parentElement);时却不编译?


文件Element.hpp

class Element{};

文件HelperFunctions.hpp

#include "Element.hpp"

namespace XYZ {
    class Something;

    template<typename T>
    T get_element(Element* e) {
    }

    template<>
    Something get_element(Element* e);
}

文件HelperFunctions.cpp

#include "HelperFunctions.hpp"
#include "Something.hpp"

namespace XYZ {
    template<>
    Something get_element(Element* e) {
       // Convert Element to Something somehow
       return Something{};
    }
}

文件SubscriptProxy.hpp

#include "HelperFunctions.hpp"

namespace XYZ {
    class Something;

    template<typename C, typename D, typename E>
    class SubscriptProxy {
        C m_parent;
        E m_index; 

        template<typename T>
        T get_element(Element* e) const {
            return XYZ::get_element<T>(e); // call helper function
        }

        template<typename T>
        bool is(int index, Element*& e) const noexcept {
            Element* parentElement;
            if (!m_parent.template is<Something>(m_index, parentElement)) {
                return false;
            }
            auto d = this->get_element<Something>(parentElement);
            return d.template is<T>(index, e);
        }
    };
}

当然还有Something.hppSomething.cpp。它包含一个返回 SubscriptProxy 实例的运算符:

#include "SubscriptProxy.hpp"
#include "HelperFunctions.hpp"

namespace XYZ {
    class Something {
        SubscriptProxy<Something, Something, int> operator[] (int index) const noexcept;
    };
}

文件Something.cpp

#include "Something.hpp"

namespace XYZ {
SubscriptProxy<Something, Something, int> Something::operator[] (int index) const noexcept {
    return SubscriptProxy<Something, Something, int>{};
}

这可以编译并正常工作。

但是,如果我将 SubscriptProxy::is 方法的实现更改为以下内容:

        template<typename T>
        bool is(int index, Element*& e) const noexcept {
            Element* parentElement;
            if (!m_parent.template is<Something>(m_index, parentElement)) {
                return false;
            }
            auto d = XYZ::get_element<Something>(parentElement);
            return d.template is<T>(index, e);
        }

...编译失败并显示错误消息:Calling 'get_element' with incomplete return type 'Something'。

为什么?

【问题讨论】:

  • 完整的可编译示例会更好。我的猜测是您使用的是前向声明,而不是类定义
  • @BЈовић 我已经修改了这个例子。现在应该可以编译了。
  • 不,你没有。见sscce.org - 它不必编译,但它必须是完整的。
  • 嗯...我做到了。创建 6 个文件,将代码复制并粘贴到其中 => Short:尽可能短,因为我不确定问题出在哪里。我不能将所有内容都放入 1 个文件中,因为几乎是循环依赖是问题的一部分;自给自足:一切都在那里;正确:它编译;示例:我正在描述问题,我尝试解决。

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


【解决方案1】:

two-phase name lookup用模板检查错误:

  • 一个用于任何模板参数,因此编译器只检查非依赖代码。
  • 一个在实例化(所以所有参数都是固定的)。

auto d = XYZ::get_element&lt;Something&gt;(parentElement); 现在不再依赖于模板,因此编译器可能会为此提供错误。

对于this-&gt;get_element,它取决于this,它是模板。

【讨论】:

  • 我希望提出原始问题的人无法理解正确答案。用更初学者的话来说:当调用不依赖于模板时,编译器希望在编译过程中更早地知道 get_element 返回的类型。但是,如果在模板实例化之前没有解析该调用,那么编译器会延迟需要知道返回类型,直到那个时候(此时必须已经看到了定义)。
  • 嗯,这是否意味着我不能直接使用XYZ::get_element而必须坚持使用this-&gt;get_element
  • 这意味着你不能在没有#include "something.h" 的情况下直接使用XYZ::get_element&lt;Something&gt; 所以你可以选择是否包含类定义(而不仅仅是前向声明)还是强制编译器延迟需要它定义。
  • 我想,我不能这样做,因为我需要 Something 中的 SubscriptProxy 的完整类型。
  • 处理这种近乎循环的依赖的一种方法是将关键的 hpp 文件分成两部分。当我这样做时,我将声明从 xxx.hpp 移动到 xxx_declare.hpp,保留 xxx.hpp 中的定义(包括 xxx_declare.hpp)然后让大多数需要 xxx 的 cpp 文件仍然包括 xxx.hpp 但大多数 hpp 包括 xxx_declare .在您的情况下,关键是在Something 所需的hpp 中定义了SubscriptProxy,但SubscriptProxy:: 是在需要Something 的不同hpp 中定义的。像您一样,我不喜欢使用该模板组合的替代方法。但它可能更常见。
猜你喜欢
  • 1970-01-01
  • 2016-05-25
  • 1970-01-01
  • 2018-06-19
  • 2011-08-04
  • 1970-01-01
  • 1970-01-01
  • 2021-05-20
  • 2023-04-08
相关资源
最近更新 更多