c++ - Visual Studio 和 Clang 不同的行为模板元编程

标签 c++ visual-studio templates namespaces clang

以下文件确实可以在 Visual Studio 编译器和 Clang for Microsoft Codegen 上编译,但结果却大不相同。

在 Visual Studio 中,它计算参数列表中动态矩阵的数量(这是我的预期行为)。相反,在 clang 中,它会计算动态矩阵的数量,直到遇到第一个静态矩阵。 (输出在main.cpp文件中,格式为(VS, Clang))

我还能够在 gcc 7.1 和 icc 17 上进行复制,它们都遵循 clang 的相同行为

删除 meta 命名空间以及添加 using 声明可以解决问题,但我不明白为什么

Working example (cl 2017 RTW vs gcc 7.1)

Pastebin for ease of use

#include <tuple>

template <size_t x = 0>
class M{};

template <>
class M<0>{};

// Note, if this is removed the problem disappears
namespace meta
{
    inline auto f()
    {
        return std::make_tuple();
    }

    template <std::size_t x, typename ... Args>
    auto f(const M<x>& , Args && ... args)
    {
        return f(args...);
    }

    template <typename ... Args>
    auto f(const M<>& first, Args && ... args)
    {
            return std::tuple_cat(std::make_tuple(first), f(args...));
    }
}

#include <iostream>


int main(int, char* [])
{

    M<1> a;
    M<> b;

    std::cout << std::tuple_size<decltype(meta::f(a, a, a))>::value << "\n"; // (0, 0)
    std::cout << std::tuple_size<decltype(meta::f(a, a, b))>::value << "\n"; // (1, 0)
    std::cout << std::tuple_size<decltype(meta::f(a, b, a))>::value << "\n"; // (1, 0)
    std::cout << std::tuple_size<decltype(meta::f(a, b, b))>::value << "\n"; // (2, 0)
    std::cout << std::tuple_size<decltype(meta::f(b, a, a))>::value << "\n"; // (1, 1)
    std::cout << std::tuple_size<decltype(meta::f(b, a, b))>::value << "\n"; // (2, 1)
    std::cout << std::tuple_size<decltype(meta::f(b, b, b))>::value << "\n"; // (3, 3)

}

输出 Visual Studio

0
1
1
2
1
2
3

输出clang/gcc/icc

0
0
0
0
1
1
3

最佳答案

我打开了一个 bug report在 clang 上,很快就发现这确实是一个错误,只是不是在 clang 中,而是在 MSVC 中。我要在这里无耻地窃取 Richard Smith 的答案:

This is an MSVC bug, due to their missing / incorrect implementation of two-phase name lookup.

Within the second definition of f:

template <std::size_t x, typename ... Args>
auto f(const M<x>& , Args && ... args)
{
    return f(args...);
}

... the third 'f' has not yet been declared and thus is not found by unqualified name lookup. So once the recursion reaches this overload, it can never "go back" to the third overload.

If the namespace is removed, the third overload can be found by argument-dependent name lookup.

关于c++ - Visual Studio 和 Clang 不同的行为模板元编程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44717602/

相关文章:

sql - 为什么我右键单击任务时没有显示 "execute task"?

c++ - 标准库方法的成员函数指针问题

visual-studio - 为什么当 Visual Studio 打开时,智能感知和代码建议停止工作?

c++ - 一个有效的程序被 man7.org 宣布为无效

c++ - 在 Visual Studio Debug模式下编译的可执行文件 : jmp to function body instead of direct address in call

c++ - QListWidget 的 QT C++ SelectedIndex

visual-studio-2010 - 如何在 Visual Studio 2010 中创建 wsdl 文件?

Python UnicodeDecodeError : 'utf8' codec can't decode byte. ..意外的代码字节

c++ - cpp中的模板

c++ - GCC ICE——替代函数语法、可变参数模板和元组