SFINAE:检测类是否具有自由功能

时间:2011-01-26 14:42:56

标签: c++ templates sfinae

有没有办法,使用SFINAE来检测给定类的自由函数是否过载?

基本上,我有以下解决方案:

struct has_no_f { };

struct has_f { };

void f(has_f const& x) { }

template <typename T>
enable_if<has_function<T, f>::value, int>::type call(T const&) {
    std::cout << "has f" << std::endl;
}

template <typename T>
disable_if<has_function<T, f>::value, int>::type call(T const&) {
    std::cout << "has no f" << std::endl;
}

int main() {
    call(has_no_f()); // "has no f"
    call(has_f()); // "has f"
}

简单地重载call不起作用,因为实际上有很多foobar类型且call函数不了解它们(基本上{{} 1}}在a里面,用户提供他们自己的类型。)

我不能使用C ++ 0x,我需要一个适用于所有现代编译器的工作解决方案。

注意:遗憾的是,similar question的解决方案无效。

2 个答案:

答案 0 :(得分:3)

#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
#include <functional>
#include <type_traits>

struct X {};
struct Y {};

__int8 f(X x) { return 0; }
__int16 f(...) { return 0; }

template <typename T> typename std::enable_if<sizeof(f(T())) == sizeof(__int8), int>::type call(T const& t) {
    std::cout << "In call with f available";
    f(t);
    return 0;
}

template <typename T> typename std::enable_if<sizeof(f(T())) == sizeof(__int16), int>::type call(T const& t) {
    std::cout << "In call without f available";
    return 0;
}

int main() {
    Y y; X x;
    call(y);
    call(x);
}

快速修改f()的返回类型会产生传统的SFINAE解决方案。

答案 1 :(得分:3)

如果允许boost,则以下代码可能符合您的目的:

#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>
using namespace boost;

// user code
struct A {};
static void f( A const& ) {}
struct B {};


// code for has_f
static void f(...); // this function has to be a free standing one

template< class T >
struct has_f {
  template< class U >
  static char deduce( U(&)( T const& ) );

  template< class U, class V >
  static typename disable_if_c< is_same< V, T >::value, char(&)[2] >::type
  deduce( U(&)( V const& ) );

  static char (&deduce( ... ))[2];

  static bool const value = (1 == sizeof deduce( f ));
};

int main()
{
  cout<< has_f<A>::value <<endl;
  cout<< has_f<B>::value <<endl;
}

但是,有严格的限制 代码假定所有用户函数都具有签名( T const& ), 所以不允许( T ) 上面的函数void f(...)似乎需要是一个独立的 功能。
如果编译器可能正常执行两个阶段的查找 所有用户函数必须出现在has_f类的定义之前 模板。
老实说,我对代码的用处并不自信,但无论如何我希望如此 这有帮助。