c++ - 重载可变参数模板方法

标签 c++ c++17 overloading variadic-templates

我的编译器很难理解这段代码,我花了几个小时才找到问题所在。

#include <utility>
#include <string>

template<typename Derived>
struct AssetLoader {
    template<typename... Args>
    void doLoad(Args&& ... args) const {
        static_cast<const Derived *>(this)->load(std::forward<Args>(args)...);
    }
};

struct TextureLoader : public AssetLoader<TextureLoader> {
    void load(const std::string &path) const {
        // some code
    }
};

struct SomeOtherLoader : public AssetLoader<SomeOtherLoader> {
    void load(const std::string &path) const {
        // some code
    }
};

template<typename DefaultLoader>
class Resources {
    AssetLoader<DefaultLoader> m_defaultLoader;

public:
    Resources(AssetLoader<DefaultLoader> defaultLoader):
        m_defaultLoader(std::move(defaultLoader)) {}

    template<typename... Args>
    void load(Args&& ... args) {
        load(m_defaultLoader, std::forward<Args>(args)...);
    }

    template<typename Loader, typename... Args>
    void load(const AssetLoader<Loader>& loader, Args&& ... args) {
        loader.doLoad(std::forward<Args>(args)...);
    }
};

int main() {
    Resources<TextureLoader> resources(TextureLoader{});
    resources.load("image.png");
    resources.load(SomeOtherLoader{}, "example.jpg");
    return 0;
}

我收到此错误:

fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)
         return load(m_defaultLoader, std::forward<Args>(args)...);
                                      ~~~~~~~~~~~~~~~~~~^~~~~~

我的真实代码要复杂得多,但我将其简化为这样,但我遇到了同样的错误。

如果我评论第一个重载,它工作得很好,但我无法在不传递 Loader 的情况下调用 load() 方法。我想要默认加载器的重载,因此我可以执行 resources.load("image.png");

我使用的是mingw64 8.1

有什么想法吗?

最佳答案

编译器准确地告诉你问题出在哪里——这里是无限递归:

template<typename... Args>
void load(Args&& ... args) {
    load(m_defaultLoader, std::forward<Args>(args)...);
}

该函数无限地调用自身。永远不会选择另一个重载,因为 Args&&合成了比 AssetLoader<Loader> const& 更好的匹配(具体来说,TextureLoader const&)。

给另一个重载一个不同的名称以消除歧义...

template<typename... Args>
void load(Args&& ... args) {
    load2(m_defaultLoader, std::forward<Args>(args)...);
}

template<typename Loader, typename... Args>
void load2(const AssetLoader<Loader>& loader, Args&& ... args) {
    loader.doLoad(std::forward<Args>(args)...);
}

关于c++ - 重载可变参数模板方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64417530/

相关文章:

c++ - 具有专用于自身的模板方法的模板类

c++ - c2664 无法将参数 2 从 'std::string' 转换为 'const void *'

c++ - C++ 中的编译时数组选择

c++ - 为什么 clang++ 报告与 "value stored to ' .. .' during its initialization is never read"的结构化绑定(bind)?

c++ - 指向 C++17 中 constexpr 静态成员的 constexpr 指针

c++ - 从抽象类中声明的重载算术运算符返回指针是否合理?

c++ - C++ 中的友元方法 "not declared in this scope"

cuda - 具有相同签名的函数

c++ - 在 C++ 中重载 ">>"和 "<<"

c++ - 派生模板覆盖成员函数 C++ 的返回类型