std::enable_if_t works with gcc and clang but does not compile with msvc

std::enable_if_t works with gcc and clang but does not compile with msvc


8

I have a friend function template operator<< that works with both gcc and clang but not with 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
}

I want to know which compiler has the correct behavior according to the c++ standard. The msvc error says:

<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)

3

  • I think it's an MSVC bug to do with enable_if. Here's a similar example stackoverflow.com/questions/74902168

    – cigien

    15 hours ago

  • 4

    There's no point asking about downvotes, especially a single one. People may not understand something and downvotes, they have a right to a single vote. Even if they don't understand due to a fault of their own, it's still their right to vote. Asking for explanations is at best going to be ignored, or at worse draw out long fruitless arguments. Discussing downvotes is a waste of time for everyone.

    – StoryTeller – Unslander Monica

    15 hours ago

  • As a workaround, making it a type parameter typename = std::enable_if_t< T{1}> seems to compile.

    – BoP

    11 hours ago

1 Answer
1


9

This is a MSVC bug and has nothing to do with the operator<< at all.

Just mentioning Foo<U> anywhere with U being a template parameter causes the error because MSVC tries to check validity of std::enable_if_t< T{1}, int> immediately, even though no concrete type for U/T is known yet. This then fails.

MSVC doesn’t correctly recognize that std::enable_if_t< T{1}, int> is a dependent type and therefore shouldn’t be checked until after a concrete U/T is substituted.

See https://godbolt.org/z/ncb3va3ro for a reduced example:

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

template<typename R>
using U = Foo<R>;  // <- same error here

3



Leave a Reply

Your email address will not be published. Required fields are marked *