繁体   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;
}

上面的程序将输出:

1
0

它显示了如果继承了push_back函数,则模板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> {};

与未来的实用程序

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>;

如果您想详细了解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;
};

在线演示

根据答案,您的代码可能如下所示:

#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;
};

所有学分归@jork

您可能已经使用了答案中的代码,但它不适用于继承的函数。

为了完整起见,我想发布另一种以前没有提到的方法。
这基于函数的定义和别名声明。
它遵循一个最小的有效示例:

#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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM