C++: why does calling std::wstring::begin() before #include <vector> cause a compiler error in this code?

╄→гoц情女王★ 提交于 2020-01-24 07:44:19

问题


This code:

#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;
}

produces the following error on line 17 (the line that calls foo()) when compiled with clang:

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) {
    ~    ^

However, if I move #include <vector> to the top of the file, the error goes away.

Why does this happen, and is there any way to work around it while a) maintaining the position of these #include statements and b) not having to rewrite foo?

Explanation:

This is relevant to a library I'm working on, because it makes it necessary to include my header before certain other headers that define inline functions that call std::string::begin(). I'd like to avoid that requirement if at all possible, especially since it's quite likely someone might nonchalantly include these other headers before mine (as it's not usually necessary to include headers in a specific order), resulting in this error to which there's no obvious fix. The offending "other headers" are in Qt's core library, and include <QString>.

My library requires defining functions that take a template-template parameters with an uncertain number of template arguments, hence my usage of template <class...> class T and why I can't rewrite foo.

Note that the only STL class that seems to have this issue is std::vector. If I change line 17 to use std::list, std::set, or one of the other STL container classes, there's no error.

edit: Since people are reporting that other compilers aren't throwing an error, I'll add that my compiler is: Apple LLVM version 8.0.0 (clang-800.0.42.1) on macOS 10.11.6.

edit2: Updated the example code to more closely match my actual use case. Before this edit foo didn't return a value, but in my library it does and needs to rely on default template arguments, so the solution proposed by @n.m. unfortunately doesn't help me.


回答1:


You can work around this issue like this:

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

I'm no longer sure it's a compiler/library bug. Perhaps the opposite is true (that is, compilers that do not emit a diagnostic message for the original code are in error). This part of the standard is rather convoluted and I'm not sure how to read it. The proposed fix seems to be correct regardless.



来源:https://stackoverflow.com/questions/40881064/c-why-does-calling-stdwstringbegin-before-include-vector-cause-a-com

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!