2015-02-16 3 views
1

У кого-то есть идея проверить, является ли произвольный метод const?Проверить, является ли метод const

Как:

static_assert(is_const<vector<int>::size>::value, "size is not const"); 
static_assert(!is_const<vector<int>::push_back>::value, "push_back is const"); 

Хороший вопрос T.C :) Я находя определенную перегрузку метода, и я хочу только установить модифицированный флаг, если метод я нашел это неконстантная.

Вот мои шаблоны и maroes:

#define FRET_DECL_TYPE(Function) \ 
    template<typename T_, typename ... Args_> \ 
    struct f_ret##Function { typedef decltype(std::declval<T_&>().Function(std::declval<Args_&&>()...)) type; }; 

#define RPROP_PROXY_METHOD(Function) \ 
     FRET_DECL_TYPE(Function) \ 
     template<typename ... Args> \ 
     typename f_ret##Function<T, Args...>::type \ 
     Function(Args&& ... args) const { return this->GetReference().Function(static_cast<Args&&>(args)...); }; \ 
     template<typename ... Args> \ 
     typename f_ret##Function<T, Args...>::type \ 
     Function(Args&& ... args) { this->SetModified(true); return this->GetReference().Function(static_cast<Args&&>(args)...); }; \ 
+7

Что должно 'is_const' возвращать на' vector :: begin'? –

+0

Возможно, это может вам помочь: http: //stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence – swang

ответ

3

Это может быть сделано с помощью “Walter Brown's void_t trick” хотя он быстро становится немного многословным, если вам это нужно для большого количества участников. Вы можете использовать макрос, чтобы избежать повторения определений шаблонов для каждого члена снова и снова.

#include <iomanip> 
#include <iostream> 
#include <type_traits> 
#include <vector> 

template<typename> 
struct void_t 
{ 
    using type = void; 
}; 

template<class C, typename = void> 
struct has_const_size : std::false_type {}; 

template<class C> 
struct has_const_size<C, typename void_t<decltype(std::declval<const C>().size())>::type> : std::true_type {}; 

template<class C, typename = void> 
struct has_const_clear : std::false_type {}; 

template<class C> 
struct has_const_clear<C, typename void_t<decltype(std::declval<const C>().clear())>::type> : std::true_type {}; 


int 
main() 
{ 
    std::cout << "std::vector<int>::size() " << std::boolalpha << has_const_size<std::vector<int>>::value << std::endl; 
    std::cout << "std::vector<int>::clear() " << std::boolalpha << has_const_clear<std::vector<int>>::value << std::endl; 
} 

Выход:

std::vector<int>::size() true 
std::vector<int>::clear() false 
+0

Спасибо за вашу помощь! – Martin

2

Моя взять на него, открыты для предложений.

Редактировать 1: Отсутствуют ref-квалификаторы. Вот быстрое и грязное решение, чтобы иметь что-то, что действительно работает.
Редактировать 2: добавлено varargs к уравнению. Реализация становится уродливой, но стиль вызова я нахожу хорошо.

#include <iostream> 

template <class... Ttypes> 
struct params {}; 

#define isConstDuet(q)         \ 
template <class T, class Tret, class... Targs>   \ 
constexpr bool isConst(Tret (T::*)(Targs...) q,   \ 
    params<Targs...> = {}) {        \ 
    return false;           \ 
}               \ 
                  \ 
template <class T, class Tret, class... Targs>   \ 
constexpr bool isConst(Tret (T::*)(Targs...) const q,  \ 
    params<Targs...> = {}) {        \ 
    return true;           \ 
}               \ 
template <class T, class Tret, class... Targs>   \ 
constexpr bool isConst(Tret (T::*)(Targs..., ...) q,  \ 
    params<Targs...> = {}) {        \ 
    return false;           \ 
}               \ 
                  \ 
template <class T, class Tret, class... Targs>   \ 
constexpr bool isConst(Tret (T::*)(Targs..., ...) const q,\ 
    params<Targs...> = {}) {        \ 
    return true;           \ 
} 

isConstDuet() 
isConstDuet(&) 
isConstDuet(&&) 
isConstDuet(volatile) 
isConstDuet(volatile&) 
isConstDuet(volatile&&) 

#undef isConstDuet 

struct S { 
    void a() {} 
    void b() const {} 
    void c(int) {} 
    void c(float) const {} 
    void d() & {} 
    void e() && {} 
    void f() volatile & {} 
    void g() volatile && {} 
    void d2() const & {} 
    void e2() const && {} 
    void f2() const volatile & {} 
    void g2() const volatile && {} 
    void h(...) {} 
    void h2(...) const {} 
}; 

int main() { 
    std::cout << std::boolalpha; 
    std::cout << isConst(&S::a) << '/' << isConst(&S::b) << '\n'; 
    std::cout << isConst(&S::c, params<int>{}) 
     << '/' << isConst(&S::c, params<float>{}) << '\n'; 
    std::cout << isConst(&S::d) << '/' << isConst(&S::d2) << '\n'; 
    std::cout << isConst(&S::e) << '/' << isConst(&S::e2) << '\n'; 
    std::cout << isConst(&S::f) << '/' << isConst(&S::f2) << '\n'; 
    std::cout << isConst(&S::g) << '/' << isConst(&S::g2) << '\n'; 
    std::cout << isConst(&S::h) << '/' << isConst(&S::h2) << '\n'; 
    return 0; 
} 

Выход:

false/true 
false/true 
false/true 
false/true 
false/true 
false/true 
false/true 
+0

Функции 'const' функции с ref квалификаторами есть также –

+0

Вам просто нужны еще 22 или около того перегрузки. –

+0

Я знал, что это не может быть так просто. Вернуться к работе ! – Quentin

1

Другое возможное решение:

#include <vector> 

struct Q { 
    void push_back(int i) const {} 
}; 

template<typename A, typename B> 
struct First { 
    typedef A type; 
}; 

template<typename T> 
constexpr typename 
First< 
    bool, 
    decltype(std::declval<T const>().push_back(4)) 
>::type 
test(int) { 
    return 0; 
} 

template<typename T> 
constexpr bool test(double) { 
    return 1; 
} 

static_assert(test<Q>(0), "bad"); 

Если метод Const, обе функции возможны, но компилятор будет выбрать один с Int аргумент, чтобы избежать преобразования. Если он не const, возможен только второй.