检查方法是否为const

时间:2015-02-16 15:17:40

标签: c++ function templates const typetraits

有人知道如何检查任意方法是否为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 :)我发现方法的特殊重载,我想只设置一个修改过的标志,如果我找到的方法是非const。

这是我的模板和色情:

#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)...); }; \

3 个答案:

答案 0 :(得分: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

答案 1 :(得分:2)

我接受它,愿意接受建议。

编辑1:缺少参考资格。这是一个快速而肮脏的解决方案,只是为了拥有真正有用的东西 编辑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

答案 2 :(得分: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,则只有第二个是可能的。