c++ - gcc 和 clang 抛出 "no matching function call"但 msvc (cl) 编译并按预期工作

标签 c++ gcc clang c++17 cl

我写了一个小的函数模板,将不同的容器连接到一个新的容器中:

#include <vector>
#include <unordered_set>
#include <string>
#include <iostream>
#include <iterator>

namespace impl
{
    template <typename OutIterator, typename Container, typename ...Containers>
    void join(OutIterator iterator, const Container& container, const Containers& ...containers)
    {        
        for (const auto& item : container)
            *iterator++ = item;

        join(iterator, containers...);  // gcc and clang cannot resolve this call
    }

    template <typename OutIterator, typename Container>
    void join(OutIterator iterator, const Container& container)
    {        
        for (const auto& item : container)
            *iterator++ = item;
    }
}

template <typename OutContainer, typename ...Containers>
OutContainer join(const Containers& ...containers)
{
    OutContainer container;
    auto it = std::inserter(container, container.end());
    impl::join(it, containers...);
    return container;
}

int main()
{
    using namespace std;
    vector<string> a = {"one"s, "two"s, "three"s};
    unordered_set<string> b = {"four"s, "five"s };
    auto res = join<unordered_set<string>>(a, b);

    for (auto& i : res)
        cout << i << "\n";

    return 0;
}

将 MSVC (cl.exe) 与/std:c++17 结合使用,代码编译并运行良好。但是用clang-6.0或gcc-7.3编译时,会抛出编译错误。 IE。海湾合作委员会说

no matching function for call to 'join(std::insert_iterator<std::unordered_set<std::__cxx11::basic_string<char> > >&)'

显然没有定义具有此签名的函数。但我不明白为什么它会尝试调用这样的函数。不应该这样解决吗

// in main()
join<unordered_set<string>>(a, b);

unordered_set<string> join(const vector<string>& a, const unordered_set<string>& b);
void impl::join(std::insert_iterator<unordered_set<string>> iterator, const vector<string>& a, const unordered_set<string>& b);
void impl::join(std::insert_iterator<unordered_set<string>> iterator, const unordered_set<string>& b);

为什么 gcc 会尝试实例化 join(std::insert_iterator<std::unordered_set<std::__cxx11::basic_string<char>>>&)

Here是使用编译器资源管理器的示例。

最佳答案

gcc 和 clang 是正确的。 MSVC 在正确的模板名称查找(即“两阶段查找”)方面仍然存在问题。

join,在join(iterator, containers...)中,是一个依赖名。找到该名称的候选人是:

  • 模板定义点的所有名称。这个查找只是找到它自己(可变参数重载),而不是另一个重载(2-arg 重载),因为它还没有被声明。
  • ADL 可以根据其参数找到的所有名称。这些参数都没有 impl 作为关联的命名空间,因此也不会找到其他重载。

在这种情况下,修复很简单:只需重新排序两个 join() 重载。这确保了 2-arg join() 将被第一个要点找到。


请注意,在 C++17 中,您甚至不需要两个重载。一个就好了:

template <typename OutIterator, typename Container, typename... Containers>
void join(OutIterator iterator, Container const& container, Container const&... containers) {
    for (auto const& item : container) {
        *iterator++ = item;
    }

    if constexpr(sizeof...(Containers) > 0) {
        join(iterator, containers...);
    }
}

还可以考虑使用 std::copy() 而不是循环。这实际上允许:

template <typename OutIterator, typename... Containers>
void join(OutIterator iterator, Container const&... containers) {
    using std::begin;
    using std::end;
    (iterator = std::copy(begin(containers), end(containers), iterator), ...);
}

关于c++ - gcc 和 clang 抛出 "no matching function call"但 msvc (cl) 编译并按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49634607/

相关文章:

c - 直接从 C 中的(共享)内存执行二进制/elf 文件

c++ - 如何使用 windows/cygwin 从 CMakeLists.txt 中的 Clion 中的 GCC 和 Clang 之间切换

c++ - 修复时 clang-tidy 插入多个 'override' 说明符

clang - LLVM:中间字节码与二进制码

c++ - C++中链表的问题

c++ - 是否可以编写一个在函数范围内使用时会提示的宏?

c++ - 在 Qt 中调整子部件大小后调整大小

c++ - 当存储新元素时,二维数组会删除元素本身

c++ - 为什么这些 un​​icode 变量名称不能与 -fextended-identifiers 一起使用? «, » 和 ≠

gcc 的 __cxa_demangle 的 C 等效项?