【问题标题】:Check if method is const检查方法是否为 const
【发布时间】:2015-02-16 15:17:40
【问题描述】:

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

这是我的模板和maro:

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

【问题讨论】:

标签: c++ function templates constants typetraits


【解决方案1】:

可以使用“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

【讨论】:

  • 感谢您的帮助!
【解决方案2】:

我的看法,欢迎提出建议。

编辑 1: 缺少引用限定符。这是一个快速而简单的解决方案,只是为了让某些东西真正有效。
编辑 2: 将可变参数添加到等式中。实现越来越难看,但我觉得调用风格很好。

#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

【讨论】:

  • const 也有带有 ref 限定符的成员函数
  • 你只需要另外 22 个左右的重载。
  • @T.C.如果你确定那个 22,你能帮我找到丢失的那一半吗?我有易失性/非易失性、值、参考和右值参考。使用 const/non-const 开关是 12。
  • @Quentin C 风格的可变参数。
  • @T.C.哎哟,什么鬼。我什至找不到关于带有可变参数的成员函数指针的信息......编辑:好的,得到了​​一些东西。现在让它工作。
【解决方案3】:

另一种可能的解决方案:

#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,则只有第二个是可能的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-12
    • 1970-01-01
    • 1970-01-01
    • 2014-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多