std::enable_if_t 可与 gcc 和 clang 一起使用,但不能与 msvc 一起编译

Ala*_*lan 12 c++ templates language-lawyer

我有一个友元函数模板operator<<,它可以与 gcc 和 clang 一起使用,但不能与 msvc 一起使用。

#include <iostream>
#include <type_traits>

template< typename T, std::enable_if_t< T{1}, int> =0 >
class Foo
{
    template< typename Ar, typename R> 
    friend Ar& operator<<(Ar& os, const Foo<R>& foo)
    {
        return os;
    }          
};

int main()
{
    Foo<int> i;
    std::cout << i;  //works with gcc and clang but does not compile with msvc
}
Run Code Online (Sandbox Code Playgroud)

我想知道哪个编译器根据 C++ 标准具有正确的行为。msvc 错误说:

<source>(4): error C2972: 'Foo': template parameter 'unnamed-parameter': the type of non-type argument is invalid
<source>(6): note: see declaration of 'Foo'
<source>(4): note: the template instantiation context (the oldest one first) is
<source>(11): note: see reference to class template instantiation 'Foo<T,__formal>' being compiled
<source>(15): error C2679: binary '<<': no operator found which takes a right-hand operand of type 'Foo<int,0>' (or there is no acceptable conversion)
Run Code Online (Sandbox Code Playgroud)

use*_*522 14

这是一个 MSVC 错误,与完全无关operator<<

只要Foo<U>在任何地方U提及模板参数就会导致错误,因为 MSVC 会尝试std::enable_if_t< T{1}, int>立即检查 / 的有效性,即使尚不知道U/的具体类型。T然后这会失败。

MSVC 无法正确识别这是一个依赖类型,因此在替换具体的/std::enable_if_t< T{1}, int>之前不应进行检查。UT

请参阅https://godbolt.org/z/ncb3va3ro了解简化示例:

template< typename T, std::enable_if_t< T{1}, int> =0 >
class Foo
{      
};

template<typename R>
using U = Foo<R>;  // <- same error here
Run Code Online (Sandbox Code Playgroud)

  • 刚刚报告:https://developercommunity.visualstudio.com/t/Premature-checking-of-template-validity/10491909 (6认同)