G ++ and clang ++ different behavior with variable template and SFINAE

Another question about the type "who is right between g ++ and clang ++?" for standard C ++ gurus.

Suppose we want to apply SFINAE to a variable template to include this variable only if the template type satisfies a certain condition.

For example: enable barif (and only if) the type of the template has a method foo()with a given signature.

Using SFINAE through an optional template type with default value

template <typename T, typename = decltype(T::foo())>
static constexpr int bar = 1;  

works for both g ++ and clang ++, but has a problem: it can be hacked explaining the second type of template

So

int i = bar<int>;

gives a compilation error where

int i = bar<int, void>;

compile without problems.

So, due to my ignorance of SFINAE, I tried to enable / disable the type of the same variable:

template <typename T>
static constexpr decltype(T::foo(), int{}) bar = 2; 

: () g++, clang++

tmp_003-14,gcc,clang.cpp:8:30: error: no member named 'foo' in 'without_foo'
static constexpr decltype(T::foo(), int{}) bar = 2;
                          ~~~^

, , : ? g++ clang++?

: ++ 14, SFINAE ?

#include <type_traits>

// works with both g++ and clang++
//template <typename T, typename = decltype(T::foo())>
//static constexpr int bar = 1;

// works with g++ but clang++ gives a compilation error
template <typename T>
static constexpr decltype(T::foo(), int{}) bar = 2;

struct with_foo
 { static constexpr int foo () { return 0; } };

struct without_foo
 { };

template <typename T>
constexpr auto exist_bar_helper (int) -> decltype(bar<T>, std::true_type{});

template <typename T>
constexpr std::false_type exist_bar_helper (...);

template <typename T>
constexpr auto exist_bar ()
 { return decltype(exist_bar_helper<T>(0)){}; }

int main ()
 {
   static_assert( true == exist_bar<with_foo>(), "!" );
   static_assert( false == exist_bar<without_foo>(), "!" );
 }
+6
1

, :

, clang missinterpretation. , bar .

-, , bar, :

template <typename T>
constexpr auto exist_bar_helper(int) -> decltype(void(T::foo()), std::true_type{});

(SFINAE ).

, , SFINAE-. bar :

template <typename T>
static constexpr decltype(void(T::foo()), int{}) bar();

- , . , decltype SFINAE (std:: false_type)... .

, GCC:

exist_bar -> exists_bar_helper -> bar (woops) -> no worries, i have alternatives
          -> exists_bar_helper(...) -> false

CLANG :

exist_bar -> exists_bar_helper -> bar (woops) // oh no
// I cannot access that var, this is unrecoverable error AAAAAAAA

, .

: SFINAE , SFINAE , " "

0

All Articles