C ++ 11查找类型是否具有成员函数或支持运算符的方法?

时间:2013-06-19 21:05:28

标签: c++ c++11

有一种(貌似)很好的C ++ 03方法可以找出一个类型是否有成员函数或运算符:

https://github.com/jaredhoberock/is_call_possible/blob/master/is_call_possible.hpp

有没有现代的C ++ 11方法呢?最好不要包含任何外部代码并仅使用标准。

4 个答案:

答案 0 :(得分:20)

这适用于GitHub中提供的所有测试用例(演示:http://ideone.com/ZLGp4R):

#include <type_traits>

template <typename C, typename F, typename = void>
struct is_call_possible : public std::false_type {};

template <typename C, typename R, typename... A>
struct is_call_possible<C, R(A...),
    typename std::enable_if<
        std::is_same<R, void>::value ||
        std::is_convertible<decltype(
            std::declval<C>().operator()(std::declval<A>()...)
            //                ^^^^^^^^^^ replace this with the member you need.
        ), R>::value
    >::type
> : public std::true_type {};

答案 1 :(得分:16)

C ++ 11增加了一个新技巧,我经常开玩笑地称之为“CFINAE”(编译失败不是错误)。

它使用decltype运算符和SFINAE的常规属性。

考虑以下功能:

template <typename X, typename Y>
static auto check(X& x, Y& y) -> decltype(x >> y);

仅在XY为类型的情况下才会在重载期间考虑 移位运算符已定义。为check添加一个常规的全部重载,你有一个机制来测试是否可以编译任意表达式。

事实上,这是Andrew Sutton(Origin提案的作者之一)在实验Concepts Lite库中开发的原则。实际上,我的示例直接来自here以实现Streamable概念。

我推荐Andrew Sutton和Bjarne Stroustrup撰写的GoingNative 2012的以下演示文稿,其中介绍了新概念和Origin库:

http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/A-Concept-Design-for-C-

答案 2 :(得分:2)

不,这几乎是一样的。或多或少。实现方式各不相同,但您可以使用标准库特征替换该实现内部使用的某些元函数。但是没有简单的方法来检测是否可以在给定一组参数的情况下调用某种类型的函数。

那是concepts (PDF)

答案 3 :(得分:1)

我使用以下基于SFINAE的众所周知的方法:

#define TYPE_SUPPORTS(ClassName, Expr)                         \
  template<typename U>                                         \
  struct ClassName                                             \
  {                                                            \
  private:                                                     \
    template<typename>                                         \
    static constexpr std::false_type test(...);                \
                                                               \
    template<typename T = U>                                   \
    static decltype((Expr), std::true_type{}) test(int) ;      \
                                                               \
  public:                                                      \
    static constexpr bool value = decltype(test<U>(0))::value; \
  };

宏的主要目的是简化添加类型检查。宏定义了一个类,允许您对类型T进行任意检查。

例如,要检查是否可以为类型调用std::begin()

namespace detail
{
  TYPE_SUPPORTS(SupportsBegin, std::begin(std::declval<T>()))
}

template<typename T>
bool supportsBegin()
{
   return detail::SupportsBegin<T>::value;
}

当然,detail命名空间和函数包装器都是语法糖,但在调用者方面稍微改进了语法。