首页 > 解决方案 > enable_if + is_same + constexpr 函数使 MSVC 失败(但在 Clang、GCC 中运行良好)

问题描述

这是一个非常简单的代码:

#include <tuple>
#include <type_traits>
#include <array>

template <class T> struct TypeHolder {};

template<class T, size_t N>
constexpr size_t array_size(TypeHolder<std::array<T,N>>)
{
    return N;
};

using AnyType = int;
template <class V, typename std::enable_if<std::is_same<V,
 std::array<typename V::value_type, array_size(TypeHolder<V>())>>::value, AnyType>::type* = nullptr>
    void test(V & v)
{

}

int main()
{
    std::array<int, 5> x;
    test(x);
}

不要问这个代码到底是干什么用的。没关系。它只是我发现的精炼和简化示例。重要的是它似乎是有效的 C++ 17 代码。

test()仅当 V 为 时才启用(在进一步的 SFINAE 情况下)std::array。是的,我知道我可以做到,template<class T, int N> void test(array<T, N>& v)但是这个更脏的模板参数在某些情况下可以帮助我没有int N. (相信我!)

无论如何,此 C++ 17代码无法在具有 C++ 17 设置的 Visual Studio 2019 中编译。但是它在 GCC 和 Clang 中运行良好。

几个小时前,我在这里发布了相关问题。我唯一能发现的共同点是它们是关于一些复杂的模板并且它们会导致相同的错误代码:

error C2672:  no matching overloaded function found
error C2783:  could not deduce template argument for '__formal'

问题是......

  1. 那是有效的 C++ 17 代码吗?
  2. 那么为什么 MSVC 编译失败呢?
  3. 和我之前的问题有什么关系?
  4. 如果我决定只使用 MSVC,我应该如何处理?

标签: c++visual-c++language-lawyer

解决方案


我不知道究竟是什么使 MSCV 的编译器跳闸,但用默认类型参数替换默认指针似乎有效:

template <typename V, typename = std::enable_if_t<std::is_same_v<V,
 std::array<typename V::value_type, array_size(TypeHolder<V>())>>, AnyType>>
    void test(V & v)

两者都应该是有效的 C++17,因为第二个参数可以从V. 也许 constexpr 函数还没有按照 MSCV 中的标准。


推荐阅读