C:为什么在#include之前调用std :: wstring :: begin()导致此代码中出现编译器错误?

这段代码:

#include <string>

void blah() {
    std::string str;
    str.begin();
}

#include <vector>

template <template <class...> class T, class U, class V, class ... Rest>
T<V> foo(const T<U, Rest...> &container, const V &arg) {
    (void)container;
    return T<V>({arg});
}

int main() {
    auto result = foo(std::vector<int>{1, 2, 3, 4, 5}, std::string("asdf"));
    return 0;
}

在使用clang编译时,在第17行(调用foo()的行)上产生以下错误:

main.cpp:17:23: error: no matching function for call to 'foo'
        auto result = foo(std::vector<int>{1, 2, 3, 4, 5}, std::string("asdf"));
                      ^~~
main.cpp:11:10: note: candidate template ignored: substitution failure [with T = vector, U = int, V = std::__1::basic_string<char>, Rest = <std::__1::allocator<int>>]: too few template arguments for class template 'vector'
    T<V> foo(const T<U, Rest...> &container, const V &arg) {
    ~    ^

但是,如果我移动#include< vector>到文件的顶部,错误就消失了.

为什么会发生这种情况,有没有办法解决这个问题,同时a)保持这些#include语句的位置,以及b)不必重写foo?

说明:

这与我正在处理的库有关,因为它需要在定义调用std :: string :: begin()的内联函数的某些其他头之前包含我的头.我想尽可能避免这个要求,特别是因为很可能有人可能会在我之前不加思索地包含这些其他标题(因为通常不需要按特定顺序包含标题),导致此错误没有明显的修复.违规的“其他标题”在Qt的核心库中,包括< QString>.

我的库需要定义函数,这些函数采用模板参数,模板参数的数量不确定,因此我使用模板< class …> T级以及为什么我不能重写foo.

请注意,似乎唯一具有此问题的STL类是std :: vector.如果我将第17行更改为使用std :: list,std :: set或其他一个STL容器类,则没有错误.

编辑:由于人们报告其他编译器没有抛出错误,我将在macOS 10.11.6上添加我的编译器:Apple LLVM版本8.0.0(clang-800.0.42.1).

edit2:更新了示例代码,以更贴近我的实际用例.在此编辑之前,foo没有返回值,但在我的库中,它确实需要依赖于默认模板参数,因此@ n.m提出了解决方案.不幸的是没有帮助我.

最佳答案 您可以像这样解决此问题:

template <template <class...> class T, class U, class ... Rest>
void foo(const T<U, Rest...> &container) {
   (void)container;
}

我不再确定它是编译器/库错误.也许情况恰恰相反(即,不为原始代码发出诊断消息的编译器出错).标准的这一部分相当复杂,我不知道如何阅读它.无论如何,建议的修复似乎是正确的.

点赞