Как проверить тип на наличие оператора без параметров () - PullRequest
7 голосов
/ 26 октября 2011

Я пытаюсь проверить, совместим ли функтор с заданным набором типов параметров и заданным типом возврата (то есть данные типы типов могут быть неявно преобразованы в фактические типы параметров и наоборот для возвращаемого типа),В настоящее время я использую следующий код для этого:

    template<typename T, typename R, template<typename U, typename V> class Comparer>
    struct check_type
    { enum {value = Comparer<T, R>::value}; };

    template<typename T, typename Return, typename... Args>
    struct is_functor_compatible
    {
        struct base: public T
        {
            using T::operator();
            std::false_type operator()(...)const;
        };
        enum {value = check_type<decltype(std::declval<base>()(std::declval<Args>()...)), Return, std::is_convertible>::value};
    };

check_type<T, V, Comparer> Это работает довольно хорошо в большинстве случаев, однако не удается скомпилировать, когда я тестирую функторы без параметров, такие как struct foo{ int operator()() const;};, потому что вв этом случае два operator() основания кажутся неоднозначными, что приводит к чему-то вроде этого:

error: call of '(is_functor_compatible<foo, void>::base) ()' is ambiguous
note: candidates are:
note: std::false_type is_functor_compatible<T, Return, Args>::base::operator()(...) const [with T = foo, Return = void, Args = {}, std::false_type = std::integral_constant<bool, false>]
note: int foo::operator()() const

Так что, конечно, мне нужен другой способ проверить это для функторов без параметров.Я попытался сделать частичную специализацию is_functor_compatible для пустого пакета параметров, где я проверяю, является ли тип &T::operator() функцией без параметров, которая работает более или менее.Однако этот подход, очевидно, дает сбой, когда у тестируемого функтора несколько operator().

. Поэтому мой вопрос заключается в том, существует ли лучший способ проверить наличие 1015 * без параметров и как это сделать.

Ответы [ 2 ]

8 голосов
/ 26 октября 2011

Когда я хочу проверить, является ли данное выражение допустимым для типа, я использую структуру, подобную этой:

template <typename T>
struct is_callable_without_parameters {
private:
    template <typename T1>
    static decltype(std::declval<T1>()(), void(), 0) test(int);
    template <typename>
    static void test(...);
public:
    enum { value = !std::is_void<decltype(test<T>(0))>::value };
};
3 голосов
/ 26 октября 2011

Вы пробовали что-то вроде:

template<size_t>
class Discrim
{
};

template<typename T>
std::true_type hasFunctionCallOper( T*, Discrim<sizeof(T()())>* );

template<typename T>
std::false_type hasFunctionCallOper( T*, ... );

После того, как вы различаете тип возвращаемого значения hasFunctionCallOper((T*)0, 0).

отредактировано (благодаря предложению Р. Мартиньо Фернандеса):

Вот код, который работает:

template<size_t n>
class CallOpDiscrim {};

template<typename T>
TrueType hasCallOp( T*, CallOpDiscrim< sizeof( (*((T const*)0))(), 1 ) > const* );
template<typename T>
FalseType hasCallOp( T* ... );

template<typename T, bool hasCallOp>
class TestImpl;

template<typename T>
class TestImpl<T, false>
{
public:
    void doTellIt() { std::cout << typeid(T).name() << " does not have operator()" << std::endl; }
};

template<typename T>
class TestImpl<T, true>
{
public:
    void doTellIt() { std::cout << typeid(T).name() << " has operator()" << std::endl; }
};

template<typename T>
class Test : private TestImpl<T, sizeof(hasCallOp<T>(0, 0)) == sizeof(TrueType)>
{
public:
    void tellIt() { this->doTellIt(); }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...