首页 > 解决方案 > 类型特征以检测具有 const 变体的特定方法的结构

问题描述

我需要一个特征来检测结构何时具有特定方法。

例如,我想检测结构何时具有两个方法void foo()and void bar(SomeData),否则为 false 。

我在下面的尝试有效,除非结构另外具有所需方法的 const 变体。我希望它也能在这种情况下工作,因为要求只是存在两个非常量变体。

即在下面的代码段中,has_methods<T>对于 是正确的TypeA,对于 是错误的TypeB

如何调整此代码以同时适用于TypeATypeB

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

template<typename T>
struct has_methods<T,
        std::void_t<decltype(&T::foo)>,
        std::void_t<decltype(&T::bar)>> : std::true_type {};

struct SomeData {};

struct TypeA
{
    void foo();
    void bar(SomeData);
};

struct TypeB
{
    void foo();
    void foo() const;
    void bar(SomeData);
    void bar(SomeData) const;
};

int main()
{
    std::cout << "has_methods<TypeA>: " << has_methods<TypeA>::value << std::endl;
    std::cout << "has_methods<TypeB>: " << has_methods<TypeB>::value << std::endl;

    return 0;
}

期望的输出是:

has_methods<TypeA>: 1
has_methods<TypeB>: 1

标签: c++templates

解决方案


请注意,您has_methods实际上并不是在测试方法。&T::foo匹配任何名为foo. 如评论中所述,您会得到误报struct C { int foo; std::string bar; };。幸运的是,您的问题的答案也解决了这个问题。

您可以使用 astatic_cast来选择所需的重载,如下所示:

template<typename T>
struct has_methods<T,
        std::void_t<decltype(static_cast<void (T::*)()>(&T::foo))>,
        std::void_t<decltype(static_cast<void (T::*)(SomeData)>(&T::bar))>> : std::true_type {};

请注意,声明SomeData必须可用(您可以将其设为 的参数has_methods,但为了简单起见,我只是重新排列了代码以SomeData首先定义)。完整示例:

#include <type_traits>
#include <iostream>

struct SomeData {};

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

template<typename T>
struct has_methods<T,
        std::void_t<decltype(static_cast<void (T::*)()>(&T::foo))>,
        std::void_t<decltype(static_cast<void (T::*)(SomeData)>(&T::bar))>> : std::true_type {};

struct TypeA
{
    void foo();
    void bar(SomeData);
};

struct TypeB
{
    void foo();
    void foo() const;
    void bar(SomeData);
    void bar(SomeData) const;
};

int main()
{
    std::cout << "has_methods<TypeA>: " << has_methods<TypeA>::value << std::endl;
    std::cout << "has_methods<TypeB>: " << has_methods<TypeB>::value << std::endl;

    return 0;
}

输出:

has_methods<TypeA>: 1
has_methods<TypeB>: 1

(我会添加一些负面因素以进行更有说服力的测试,但我不想对您的代码进行不必要的更改,并且部分是懒惰;)


推荐阅读