Can't detect T::value() using auto to parametrize true_type
Asked Answered
T

1

7

Using SFINAE, has_value_int<T> and has_value_auto<T> both try to detect whether class T has a static constexpr function named value.

  • Using int to parametrize true_type, has_value_int<T> works for demo classes pass and fail.
  • Using auto to parameterize true_type, has_value_auto<T> always returns false.

What's the difference between using int and using auto, and why does auto not work?

Specifically, why does overload resolution prefer match_auto(...) to match_auto(int)?

#include <iostream>

using namespace std;

// parametrize true_type 
template <int> using true_int = true_type; // works
template <auto> using true_auto = true_type; // does not work

// detect if T::value() is a valid compile-time expression
template <class T> true_int<(T::value(), void(), 0)> match_int(int);
template <class T> true_auto<(T::value(), void(), 0)> match_auto(int);
template <class> false_type match_int(...); // sometimes called
template <class> false_type match_auto(...); // always called
template <class T>
static constexpr bool has_value_int = decltype(match_int<T>(0))::value;
template <class T>
static constexpr bool has_value_auto = decltype(match_auto<T>(0))::value;

template <class T>
void demo() {
    cout << has_value_int<T> << "(int), " // sometimes false
            << has_value_auto<T> << "(auto)" << endl; // always false
}

int main() {
    struct pass { static constexpr int value() { return 1; } };
    using fail = float;

    cout << "has_value<pass> = "; demo<pass>(); // 1(int), 0(auto)
    cout << "has_value<fail> = "; demo<fail>(); // 0(int), 0(auto)

    return 0;
}

EDIT: Compiled using gcc 7.3.0. Same with clang works.

Taliped answered 27/7, 2018 at 15:34 Comment(6)
I smell a gcc bug :)Poeticize
I wonder if auto is less specific than (...).Taliped
Works with clang and VC++ (/std:c++17)Terms
Submitted 86703.Thole
Unrelated, it's not "ADL" preferring one to the other... it's overload resolution. ADL doesn't play a role here.Thole
@Barry: Thanks, I've edited my question to reflect this.Taliped
P
2

There is no difference; this is a gcc bug, reported by Barry as #86703.

As a workaround, don't use functions:

// detect if T::value() is a valid compile-time expression
template <typename T, typename = void> struct match_auto : std::false_type {};

template <typename T>
struct match_auto<T, std::void_t<true_auto<(T::value(), void(), 0)>>>
    : std::true_type {};

template <class T> static constexpr bool has_value_auto = match_auto<T>::value;
Poeticize answered 27/7, 2018 at 16:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.