如何检查类型是否存在无参数运算符()

发布于 2024-12-12 04:58:12 字数 1471 浏览 0 评论 0原文

我试图检查函子是否与给定的一组参数类型和给定的返回类型兼容(也就是说,给定的参数类型可以隐式转换为实际的参数类型,而返回类型则相反)。目前我使用以下代码:

    template<typename T, typename R, template<typename U, typename V> class Comparer>
    struct check_type
    { enum {value = Comparer<T, R>::value}; };

    template<typename T, typename Return, typename... Args>
    struct is_functor_compatible
    {
        struct base: public T
        {
            using T::operator();
            std::false_type operator()(...)const;
        };
        enum {value = check_type<decltype(std::declval<base>()(std::declval<Args>()...)), Return, std::is_convertible>::value};
    };

check_type 这在大多数情况下工作得很好,但是当我测试像 struct foo{ int operator()() const;}; 这样的无参数函子时,它无法编译,因为在这种情况下,两个基类的 operator() 显然是不明确的,导致了这样的结果:

error: call of '(is_functor_compatible<foo, void>::base) ()' is ambiguous
note: candidates are:
note: std::false_type is_functor_compatible<T, Return, Args>::base::operator()(...) const [with T = foo, Return = void, Args = {}, std::false_type = std::integral_constant<bool, false>]
note: int foo::operator()() const

所以显然我需要一种不同的方法来检查无参数函子。我尝试对空参数包进行 is_functor_complete 的部分特化,在其中检查 &T::operator() 的类型是否是无参数成员函数,这更有效或更少。然而,当测试函子有多个operator()时,这种方法显然会失败。

因此,我的问题是是否有更好的方法来测试无参数 operator() 是否存在以及如何执行。

I'm trying to check whether a functor is compatible with a given set of parametertypes and a given return type (that is, the given parametertypes can be implicitely converted to the actual parametertypes and the other way around for the return type). Currently I use the following code for this:

    template<typename T, typename R, template<typename U, typename V> class Comparer>
    struct check_type
    { enum {value = Comparer<T, R>::value}; };

    template<typename T, typename Return, typename... Args>
    struct is_functor_compatible
    {
        struct base: public T
        {
            using T::operator();
            std::false_type operator()(...)const;
        };
        enum {value = check_type<decltype(std::declval<base>()(std::declval<Args>()...)), Return, std::is_convertible>::value};
    };

check_type<T, V, Comparer>
This works quite nicely in the majority of cases, however it fails to compile when I'm testing parameterless functors like struct foo{ int operator()() const;};, beccause in that case the two operator() of base are apperently ambigous, leading to something like this:

error: call of '(is_functor_compatible<foo, void>::base) ()' is ambiguous
note: candidates are:
note: std::false_type is_functor_compatible<T, Return, Args>::base::operator()(...) const [with T = foo, Return = void, Args = {}, std::false_type = std::integral_constant<bool, false>]
note: int foo::operator()() const

So obvoiusly I need a different way to check this for parameterless functors. I tried making a partial specialization of is_functor_compatible for an empty parameterpack, where I check if the type of &T::operator() is a parameterless memberfunction, which works more or less. However this approach obviously fails when the tested functor has several operator().

Therefore my question is if there is a better way to test for the existence of a parameterless operator() and how to do it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

慈悲佛祖 2024-12-19 04:58:12

当我想测试给定表达式对于某种类型是否有效时,我使用与此类似的结构:

template <typename T>
struct is_callable_without_parameters {
private:
    template <typename T1>
    static decltype(std::declval<T1>()(), void(), 0) test(int);
    template <typename>
    static void test(...);
public:
    enum { value = !std::is_void<decltype(test<T>(0))>::value };
};

When I want to test if a given expression is valid for a type, I use a structure similar to this one:

template <typename T>
struct is_callable_without_parameters {
private:
    template <typename T1>
    static decltype(std::declval<T1>()(), void(), 0) test(int);
    template <typename>
    static void test(...);
public:
    enum { value = !std::is_void<decltype(test<T>(0))>::value };
};
A君 2024-12-19 04:58:12

您是否尝试过类似的操作:

template<size_t>
class Discrim
{
};

template<typename T>
std::true_type hasFunctionCallOper( T*, Discrim<sizeof(T()())>* );

template<typename T>
std::false_type hasFunctionCallOper( T*, ... );

之后,您区分了返回类型
hasFunctionCallOper((T*)0, 0)

编辑(感谢 R. Martinho Fernandes 的建议):

这是有效的代码:

template<size_t n>
class CallOpDiscrim {};

template<typename T>
TrueType hasCallOp( T*, CallOpDiscrim< sizeof( (*((T const*)0))(), 1 ) > const* );
template<typename T>
FalseType hasCallOp( T* ... );

template<typename T, bool hasCallOp>
class TestImpl;

template<typename T>
class TestImpl<T, false>
{
public:
    void doTellIt() { std::cout << typeid(T).name() << " does not have operator()" << std::endl; }
};

template<typename T>
class TestImpl<T, true>
{
public:
    void doTellIt() { std::cout << typeid(T).name() << " has operator()" << std::endl; }
};

template<typename T>
class Test : private TestImpl<T, sizeof(hasCallOp<T>(0, 0)) == sizeof(TrueType)>
{
public:
    void tellIt() { this->doTellIt(); }
};

Have you tried something like:

template<size_t>
class Discrim
{
};

template<typename T>
std::true_type hasFunctionCallOper( T*, Discrim<sizeof(T()())>* );

template<typename T>
std::false_type hasFunctionCallOper( T*, ... );

After, you discriminate on the return type of
hasFunctionCallOper((T*)0, 0).

EDITED (thanks to the suggestion of R. Martinho Fernandes):

Here's the code that works:

template<size_t n>
class CallOpDiscrim {};

template<typename T>
TrueType hasCallOp( T*, CallOpDiscrim< sizeof( (*((T const*)0))(), 1 ) > const* );
template<typename T>
FalseType hasCallOp( T* ... );

template<typename T, bool hasCallOp>
class TestImpl;

template<typename T>
class TestImpl<T, false>
{
public:
    void doTellIt() { std::cout << typeid(T).name() << " does not have operator()" << std::endl; }
};

template<typename T>
class TestImpl<T, true>
{
public:
    void doTellIt() { std::cout << typeid(T).name() << " has operator()" << std::endl; }
};

template<typename T>
class Test : private TestImpl<T, sizeof(hasCallOp<T>(0, 0)) == sizeof(TrueType)>
{
public:
    void tellIt() { this->doTellIt(); }
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文