为什么Stroustup书中的has_f无法正常工作?

时间:2018-10-29 20:49:11

标签: c++

#include <iostream>
#include <type_traits>

struct Y {
void f(int i) {}
 };

 template<bool B,typename T=void>
 using Enable_if = typename std::enable_if<B, T>::type;

 struct substitution_failure {};

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

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

 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>()));
 };

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


  template<typename T>
  constexpr bool Has_f() {
  return has_f<T>::value;
}


 template<typename T>
 class X {
public:
template<typename U=T>
 Enable_if<Has_f<U>()> use_f(const U& t) {
    f(t);
 }

  };


 int main()
{
std::cout << Has_f<Y>();
}

我知道这个问题在SO上可能是重复的,一式三份或n重复的,但是我没有找到令人信服的答案,因此我将重新发布该问题。为什么上面的代码说明Y具有没有 f函数。我使用Visual Studio 2017和GCC 7.3.0进行了尝试。我还在SO中找到了更简单的代码,可以正常工作。但是我不明白为什么这段代码不起作用。起作用的代码如下:

#include <iostream>
#include <type_traits>
using namespace std;


 struct Hello
{
int helloworld() { return 0; }
};

 struct Generic {};

 // SFINAE test
template <typename T>
class has_helloworld
{
typedef char one;
typedef long two;

template <typename C> static one test(decltype(&C::helloworld));
template <typename C> static two test(...);

public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
};

int main() {

std::cout << has_helloworld<Hello>::value << std::endl;
std::cout << has_helloworld<Generic>::value << std::endl;
std::getchar();
return 0;

}

1 个答案:

答案 0 :(得分:1)

Stroustrup的代码检查是否有使用该类型的单个参数的自由函数。相反,您的Y类具有成员函数。

也就是说,他的代码采用类型T,并检查调用f(instance of T)的格式是否正确。您可以在use_f中看到此内容。您的代码需要调用(instance of T).f(instance of int)

定义Y类以完成检查causes an output of 1

struct Y {};

void f(Y);

或者,change the check与您的班级一起工作,也要注意更改const,因为您的成员函数是非常量的:

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