Test if calling f (x) is possible using metaprogramming

The Stroustrup book gives an example of how to answer the question: “Can I call f(x)if it xhas a type x” (section 28.4.4 “Additional examples with Enable_if”). I tried to reproduce the example, but got something wrong and cannot understand that.

There is a function in my code below f(int). I expect then the result has_f<int>::valueis equal to 1( true). Actual result 0( false).

#include <type_traits>
#include <iostream>

//
// Meta if/then/else specialization
//
struct substitution_failure { };

template<typename T>
struct substitution_succeeded : std::true_type { };

template<>
struct substitution_succeeded<substitution_failure> : std::false_type { };

//
// sfinae to derive the specialization
//
template<typename T>
struct get_f_result {
private:
  template<typename X>
    static auto check(X const& x) -> decltype(f(x));
  static substitution_failure check(...);
public:
  using type = decltype(check(std::declval<T>()));
};

//
// has_f uses the derived specialization
//
template<typename T>
struct has_f : substitution_succeeded<typename get_f_result<T>::type> { };

//
// We will check if this function call be called,
// once with "char*" and once with "int".
//
int f(int i) {
  std::cout << i;
  return i;
}

int main() {
  auto b1{has_f<char*>::value};
  std::cout << "test(char*) gives: " << b1 << std::endl;
  std::cout << "Just to make sure we can call f(int): ";
  f(777);
  std::cout << std::endl;
  auto b2{has_f<int>::value};
  std::cout << "test(int) gives: " << b2 << std::endl;
}

Output:

test(char*) gives: 0
Just to make sure we can call f(int): 777
test(int) gives: 0
+4
source share
2 answers

, f :

template<typename X>
static auto check(X const& x) -> decltype(f(x));

f, , check() (none) , X. X - int, , f. ADL int, , get_f_result. .


has_f . substitution_succeeded. check() :

template<typename T>
struct has_f {
private:
    template <typename X>
    static auto check(X const& x)
        -> decltype(f(x), std::true_type{});

    static std::false_type check(...);
public:
  using type = decltype(check(std::declval<T>()));
};

has_f<T>::type true_type, false_type.


, . , ( Yakk, std::is_detected):

namespace impl {
    template <template <class...> class, class, class... >
    struct can_apply : std::false_type { };

    template <template <class...> class Z, class... Ts>
    struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...> : std::true_type { };
};

template <template <class... > class Z, class... Ts>
using can_apply = impl::can_apply<Z, void, Ts...>;

:

template <class T>
using result_of_f = decltype(f(std::declval<T>()));

template <class T>
using has_f = can_apply<result_of_f, T>;    
+5

, :

  • f. , get_f_result.

int f(int); template<typename T> struct get_f_result { private: template<typename X> static auto check(X const& x) -> decltype(f(x)); static substitution_failure check(...); public: using type = decltype(check(std::declval<T>())); };

  1. - , f(c), , int:
//
// sfinae to derive the specialization
//
template <typename Func, Func f, typename T>
struct get_f_result {
private:
  template <typename X>
    static auto check(X const& x) -> decltype(f(x));
  static substitution_failure check(...);
public:
  using type = decltype(check(std::declval<T>()));
};

:

template <typename T>
struct has_f : substitution_succeeded <typename get_f_result::type> { };

f. , .

+2

Source: https://habr.com/ru/post/1649958/


All Articles