С++ 11 способов поиска, если тип имеет функцию-член или поддерживает оператор?

Существует (по-видимому) хороший способ С++ 03 выяснить, имеет ли тип функцию-член или оператор:

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

Нет ли современного способа С++ 11 для этого? Лучше не включать внешний код и использовать только стандарт.

Ответ 1

Нет, это почти так же. Более или менее. Реализации различаются, хотя вы можете заменить некоторые метафайлы, используемые внутри этой реализацией со стандартными библиотечными чертами. Но нет простого способа определить, можно ли вызывать функцию для некоторого типа с заданным набором аргументов.

Это для концепций (PDF).

Ответ 2

Это работает со всеми тестовыми примерами, приведенными в GitHub (Demo: 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 {};

Ответ 3

С++ 11 добавляет новый трюк, который я часто шутливо называю "CFINAE" (сбой компиляции не является ошибкой).

Он использует оператор decltype и регулярные свойства SFINAE.

Рассмотрим следующую функцию:

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

Это будет учитываться при перегрузке, только если X и Y являются типами, для которых оператор сдвига. Добавьте регулярную перегрузку для check и у вас есть механизм для проверки возможности компиляции произвольного выражения.

И действительно, это принцип, разработанный в экспериментальной библиотеке Origin Эндрю Саттон (один из авторов Концепция Lite). Фактически, мой пример берется прямо из здесь для реализации Streamable.

Я рекомендую следующую презентацию от GoingNative 2012 от Andrew Sutton и Bjarne Stroustrup, где они дают представление о новых концепциях и библиотеке Origin:

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

Ответ 4

Я использую следующий хорошо известный подход, основанный на 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 является синтаксическим сахаром, но немного улучшает синтаксис на стороне вызывающего абонента.