简体   繁体   English

如何在编译时检查类是否具有继承的函数?

[英]How to check if a class has an inherited function at compile-time?

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

using namespace std;

template<typename Coll>
class has_push_back
{
    using coll_type = decay_t<Coll>;
    using True = char(&)[1];
    using False = char(&)[2];

    template<typename U, void(U::*)(const typename U::value_type&)>
    struct SFINAE {};

    template<typename T>
    static True Test(SFINAE<T, &T::push_back>*);

    template<typename T>
    static False Test(...);

public:
    enum { value = sizeof(Test<coll_type>(nullptr)) == sizeof(True) };
};

class MyColl : public vector<int> {};

int main()
{
    cout << has_push_back<vector<int>>::value << endl;
    cout << has_push_back<MyColl>::value << endl;
}

The program above will output: 上面的程序将输出:

1
0

It shows the template has_push_back doesn't work if the function push_back is inherited. 它显示了如果继承了push_back函数,则模板has_push_back不起作用。

Is there a way to make it work even if it is inheried? 即使经过修复,有没有办法使它起作用?

Here's a solution using void_t , which is standard in C++17 and also comes with additional utilities such as is_detected_exact in the Library Fundamentals v2 TS, taking most of the work out of has_push_back : 这里有一个解决方案使用void_t ,这是在C ++ 17标准,还配备了额外的工具,如is_detected_exact在图书馆基础V2 TS,同时大部分的工作出的has_push_back

template<typename... Ts>
using void_t = void;

template<typename T>
using push_back_test = decltype(std::declval<T>().push_back(std::declval<typename T::const_reference>()));

template<typename T, typename = void>
struct has_push_back : std::false_type {};

template<typename T>
struct has_push_back<T, void_t<push_back_test<T>>> : std::is_same<push_back_test<T>, void> {};

Or with future utilities : 与未来的实用程序

template<typename T>
using push_back_test = decltype(std::declval<T>().push_back(std::declval<typename T::const_reference>()));

template<typename T>
using has_push_back = std::experimental::is_detected_exact<void, push_back_test, T>;

If you'd like to learn about void_t in detail, I suggest checking out Walter Brown's CppCon 2015 talks . 如果您想详细了解void_t ,建议您查看Walter Brown的CppCon 2015演讲

template<typename Coll>
struct has_push_back {
    template<
        typename T,
        typename = decltype(
            std::declval<T&>().push_back(std::declval<typename T::value_type>())
        )
    >
    static std::true_type Test(int);

    template<typename T>
    static std::false_type Test(long);

    using type = decltype(Test<Coll>(0));
    static constexpr bool value = type::value;
};

Online Demo 在线演示

According to this answer, your code could look like this: 根据答案,您的代码可能如下所示:

#include <type_traits>

// Primary template with a static assertion
// for a meaningful error message
// if it ever gets instantiated.
// We could leave it undefined if we didn't care.

template<typename, typename T>
struct has_push_back {
    static_assert(
        std::integral_constant<T, false>::value,
        "Second template parameter needs to be of function type.");
};

// specialization that does the checking

template<typename C, typename Ret, typename... Args>
struct has_push_back<C, Ret(Args...)> {
private:
    template<typename T>
    static constexpr auto check(T*)
    -> typename
        std::is_same<
            decltype( std::declval<T>().push_back( std::declval<Args>()... ) ),
            Ret    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        >::type;  // attempt to call it and see if the return type is correct

    template<typename>
    static constexpr std::false_type check(...);

    typedef decltype(check<C>(0)) type;

public:
    static constexpr bool value = type::value;
};

All credits to @jork 所有学分归@jork

You've probably used code from this answer but it isn't working with inherited functions. 您可能已经使用了答案中的代码,但它不适用于继承的函数。

For the sake of completeness, I'd like to post another approach not previously mentioned. 为了完整起见,我想发布另一种以前没有提到的方法。
This is based on functions' definitions and an alias declaration. 这基于函数的定义和别名声明。
It follows a minimal, working example: 它遵循一个最小的有效示例:

#include <vector>
#include <type_traits>
#include<utility>

using namespace std;

template<typename T, typename... U>
constexpr auto f(int)
-> std::conditional_t<false, decltype(std::declval<T>().push_back(std::declval<U>()...)), std::true_type>;

template<typename, typename...>
constexpr std::false_type f(char);

template<typename T, typename... U>
using has_push_back = decltype(f<T, U...>(0));

class MyColl : public vector<int> {};

int main() {
    static_assert(has_push_back<vector<int>, int>::value, "!");
    static_assert(has_push_back<MyColl, int>::value, "!");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如果函数具有外部链接,则在编译时检查 - Check at compile-time if function has external linkage 在编译时检测类是否具有成员变量或函数 - Detecting at compile-time whether a class has a member variabe or function 如何检查类是否具有特定功能以避免编译时问题? - How to check if a class has specific function to avoid compile time issues? 如何在编译时检测类的声明? - How to detect declaration of class at compile-time? 如何声明一个对字符串不执行任何操作、与其他策略具有一致签名并在编译时评估的策略类 - How to declare a policy class that does nothing to a string, has consistent signature with other policies and is evaluated at compile-time 在编译时检查函数是否具有C链接[无法解决] - Checking if a function has C-linkage at compile-time [unsolvable] c ++编译时检查函数参数 - c++ compile-time check function arguments {fmt}:总是在 function 中编译时检查格式字符串 - {fmt}: always compile-time check format string in function 如果可以使用一组特定参数调用的函数存在,如何在编译时检查? - How to check at compile-time if a function that can be called with a specific set of arguments exists? 编译时类继承 - Compile-time class inhertiance
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM