【问题标题】:Type traits to check if class has member function键入特征以检查类是否具有成员函数
【发布时间】:2017-06-15 15:51:39
【问题描述】:

尝试创建一种方法来识别给定类是否具有可以调用的给定函数,并返回某种类型。

知道我在这里做错了什么吗?有没有更好的方法来确定给定方法是否可以在给定类的情况下调用?

#include <string>
#include <type_traits>

#define GENERATE_HAS_MEMBER_FUNC(func, rettype)                                \
template<typename T, class Enable = void> struct has_##func;                   \
template<typename T, class U> struct has_##func : std::false_type {};          \
template<typename T>                                                           \
struct has_##func<T,                                                           \
                  typename std::enable_if<std::is_same<                        \
                      typename std::result_of<decltype (&T::func)(T)>::type,   \
                      rettype>::value>::type> : std::true_type{};              \
template<class T> constexpr bool has_##func##_v = has_##func<T>::value;

GENERATE_HAS_MEMBER_FUNC(str, std::string)
GENERATE_HAS_MEMBER_FUNC(str2, std::string)
GENERATE_HAS_MEMBER_FUNC(funca, std::string)
GENERATE_HAS_MEMBER_FUNC(strK, std::string)
GENERATE_HAS_MEMBER_FUNC(fancy, std::string)
GENERATE_HAS_MEMBER_FUNC(really, std::string)

struct A1 {
    virtual std::string str() const { return ""; }
    std::string strK() const { return ""; }
    virtual std::string fancy()=0;
};

struct A2 : A1 {
    std::string str() const override { return ""; }
    std::string funca();
    std::string fancy() override { return ""; }
    std::string really(int a=0) const { return std::to_string(a); }

};

int main() {
    static_assert(has_str_v<A1>,
        "A1::str is virtual method with impl on base"); // MSVC: NO, clang: OK, GCC: NO
    static_assert(has_strK_v<A1>,
        "A1::strK is implemented inline "); // MSVC: NO, clang: OK, GCC: NO
    static_assert(has_fancy_v<A1>,
        "A1::fancy is a pure virtual method on base"); // MSVC: NO, clang: OK, GCC: NO
    static_assert(!has_really_v<A1>,
        "A1::really doesn't exist in A1"); // MSVC: OK, clang: OK, GCC: OK

    static_assert(has_str_v<A2>,
        "A2::str is override method "); // MSVC: OK, clang: OK, GCC: OK
    static_assert(!has_str2_v<A2>,
        "A2::str2 does not exist in A2"); // MSVC: NO, clang: OK, GCC: OK
    static_assert(has_funca_v<A2>,
        "A2::funca is defined (no impl) in A2"); // MSVC: OK, clang: OK, GCC: OK
    static_assert(has_strK_v<A2>,
        "A2::strK is implemented method on base"); // MSVC: OK, clang: OK, GCC: OK
    static_assert(has_fancy_v<A2>,
        "A1::fancy is a override of pure virtual method of base"); // MSVC: OK, clang: OK, GCC: OK
    static_assert(has_really_v<A2>,
        "A2::really has default param (can be invoked without params)"); // MSVC: OK, clang: NO, GCC: NO
    return 0;
}

这个实现的一些惊喜。

编辑: 在尝试实施@Jarod42 和@Vittorio Romeo 时,很棒的建议:

#define GENERATE_HAS_MEMBER_FUNC(func, rettype)                                \
template<class T> using _has_##func_chk =                                      \
      decltype(std::declval<T &>().func());                                    \
template<class T> constexpr bool has_##func##_v =                             \
      is_detected_exact_v<rettype, _has_##func_chk, T>;

现在两个测试用例在 VS2015 上仍然失败(没有任何意义): static_assert(!has_really_v, "A1::really 不存在于 A1"); static_assert(!has_str2_v, "A2::str2 不存在于 A2");

我可能遗漏了一些愚蠢的东西......有什么线索吗?

【问题讨论】:

  • 你看过std::is_detected(C++17,但可以在C++11中实现)吗?

标签: c++ c++14 typetraits


【解决方案1】:

是否有更好的方法来确定给定方法是否可以在给定类的情况下调用?

是的,您可以使用detection idiom,它可以在 C++11 中实现(链接页面包含有效实现)

这里有一个例子:Catfloat Cat::purr(int) 方法吗?

struct Cat { float purr(int){} };

template<class T>
using has_purr = 
    decltype(std::declval<T&>().purr(std::declval<int>()));

static_assert(std::experimental::is_detected_exact_v<float, has_purr, Cat>);

wandbox example


所需的检测习语 C++17 依赖项在 C++11 中实现是微不足道的:

template< class... >
using void_t = void;

struct nonesuch {
    nonesuch() = delete;
    ~nonesuch() = delete;
    nonesuch(nonesuch const&) = delete;
    void operator=(nonesuch const&) = delete;
};

这是fully C++11-compliant minimal example on wandbox

【讨论】:

  • 非常感谢。我正在尝试在 MSVC 中实现并运行相同的测试。但是做一些小改动来快速测试你的 wandbox 代码中的场景,看起来这确实是最好的方法,
  • 跨编译器的结果更加一致,但是有几个测试失败了......我的错误有多愚蠢? (看不到):P
  • @nCoder:你能在 wandbox 上发布一个有错误的最小示例吗?
  • godbolt.org/g/qJ09hr(澄清一下:只有 MSVC2015 在抱怨——我想我需要找到适用于 VC 的东西)
  • 您列出的 C++17 依赖项(void_tnonesuch)不是您的检测习惯使用的(std::experimental::is_detected_exact_v)。
猜你喜欢
  • 2011-01-08
  • 2022-12-12
  • 1970-01-01
  • 2020-07-08
  • 1970-01-01
  • 1970-01-01
  • 2016-05-02
  • 1970-01-01
  • 2020-10-12
相关资源
最近更新 更多