enable_if works with gcc but not with clang and msvc
Asked Answered
F

1

6

I learnt about the SFINAE principle and its various uses. Then I wrote the following program that compiles with gcc but not with msvc and clang. Live demo.

#include <iostream>
#include <type_traits>

template <typename T> class Container {
    public:

        template<typename U = T> 
        std::enable_if_t<std::is_same_v<T, int>> foo(const T&)
        {

        }
};

template<typename T>
void func(T&& callable)
{
    Container<int> c;
    (c.*callable)(4);
}
int main(){

    //works with gcc but not with clang and msvc
    func(&Container<int>::foo); 
} 

As we can see the above program works with gcc but not with clang and msvc and I don't know which compiler is right here. So is this program well-formed or ill-formed etc.

Faceless answered 25/11, 2022 at 13:8 Comment(5)
The problem isn't about enable_if. Change it to void and you should get the same errors.Wingo
Cool. Works ok if explicitly specialize foo<int> at the point where a pointer to the foo is taken. Also, it's either member functions are automatically "skipped" when not used so you don't need to disable them, or there are more than one such function and all-but-one are disabled for each "taking of a pointer", but then you still have to disambiguate somehow which function you're interested in when taking a pointer to it. Do you have a use-case?Veery
The program is well-formed due to CWG 2608.Bloodsucker
BTW, your enable_if usage is wrong: instantiating Container<char> would produce hard error, you need std::enable_if_t<std::is_same_v<U, int>>. In C++20, a requires(std::is_same_v<T, int>) (and remove the template) would simplify things.Aloke
What compile error(s) did you receive from clang and msvc?Schopenhauerism
B
9

This is CWG 2608 and the program is well-formed.

If all of the template arguments can be deduced or obtained from default template-arguments, they may all be omitted; in this case, the empty template argument list <> itself may also be omitted.

(emphasis mine)

Note the added part which makes func(&Container<int>::foo); well-formed as the template argument for U can be obtained from the default template argument and hence it may be omitted which implies that the empty template argument list <> itself may also be omitted. Thus, gcc is standard conformant.

Here is the clang bug:

Clang rejects valid program with default argument

Here is the msvc bug:

MSVC rejects valid program with default argument

Bloodsucker answered 25/11, 2022 at 13:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.