首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用于分类私有函数的元编程技巧

用于分类私有函数的元编程技巧
EN

Stack Overflow用户
提问于 2015-04-17 20:46:18
回答 1查看 1.1K关注 0票数 4

这是一个关于C++编译时自省的问题。

是否有已知的技巧来检测匹配函数实际上是私有的,因此不能被调用?我凭直觉猜测这是不可能的--但也许我错了?

说明:使用元编程技术(主要基于SFINAE机制),可以在作为模板参数的类型中检测属性(嵌套类型、成员、具有特定签名的函数)的存在(即我们知道存在这种类型,但我们对该类型不了解更多)。基于这种内省谓词,就有可能创建专门的实现、适配器等。

现在,具体的问题是,这样的谓词可能与类的私有成员匹配。当我们随后根据(false)匹配的结果生成代码时,编译会失败,因为我们实际上不允许访问该成员。因此,找出这种虚假匹配的技术是很好的.

EN

回答 1

Stack Overflow用户

发布于 2015-04-18 01:14:10

好吧,我从不用它。这只是个主意。

因此,要想检测函数是否存在,我们需要如下所示:

代码语言:javascript
复制
#include <iostream>

#define DEFINE_METHOD_CHECKER(RETURN_TYPE, METHOD_NAME, PARAMETERS)     \
template<typename T>                                                    \
struct Is ## METHOD_NAME ## MemberFunctionExists                        \
{                                                                       \
private:                                                                \
    typedef char True;                                                  \
    typedef char (&False)[2];                                           \
    template<typename U, RETURN_TYPE (U::*)PARAMETERS = &U::METHOD_NAME>\
    struct Checker                                                      \
    {                                                                   \
        typedef True Type;                                              \
    };                                                                  \
    template<typename U>                                                \
    static typename Checker<U>::Type Tester(const U*);                  \
    static False Tester(...);                                           \
public:                                                                 \
    enum { value = (sizeof(Tester(static_cast<const T*>(0))) == sizeof(True)) }; \
}

// IsMethodMemberFunctionExists<T>::value
DEFINE_METHOD_CHECKER(int, Method, (bool));
// IsTestMemberFunctionExists<T>::value
DEFINE_METHOD_CHECKER(int*, Test, (int&, char));

class Exists
{
public:
    int Method(bool);
    int* Test(int&, char);
};

class NotExists
{
};

int main()
{
   std::cout << IsMethodMemberFunctionExists<Exists>::value << std::endl;
    std::cout << IsTestMemberFunctionExists<Exists>::value << std::endl;

    std::cout << IsMethodMemberFunctionExists<NotExists>::value << std::endl;
    std::cout << IsTestMemberFunctionExists<NotExists>::value << std::endl;
}


Output:
1
1
0
0

Live

好的。如果我评论public: --函数将是私有的,我们的检测器将打印0 --这样的成员函数不存在(“违反访问控制确实会导致C++11中的替换失败”)。如@T.C.所说):

代码语言:javascript
复制
class Exists
{
//public:
    int Method(bool);
    int* Test(int&, char);
};

Output:
0
0
0
0

Live

现在,为了检测,如果给定的函数是私有的,我们将通过抽象类公开它。简而言之:

代码语言:javascript
复制
struct ITest
{
    virtual void foo() = 0;
};

class Test : ITest
{
    // foo() is private AND it's override Itest::foo() !
    void foo();
}

// std::is_abstract<Test>() yields false !

所以,一起

代码语言:javascript
复制
#define DEFINE_PRIVATE_METHOD_CHECKER(RETURN_TYPE, METHOD_NAME, PARAMETERS) \
DEFINE_METHOD_CHECKER(RETURN_TYPE, METHOD_NAME, PARAMETERS); \
template<typename T> \
struct IsPrivate ## METHOD_NAME ## MemberFunctionExists \
{ \
public: \
    struct IOverrideTest \
    { \
        virtual RETURN_TYPE METHOD_NAME PARAMETERS = 0; \
    }; \
    \
    class OverrideTest : T, IOverrideTest {}; \
    \
public: \
    enum { value = !IsMethodMemberFunctionExists<T>::value && !std::is_abstract<OverrideTest>::value }; \
}

// IsPrivateMethodMemberFunctionExists<T>::value
DEFINE_PRIVATE_METHOD_CHECKER(int, Method, (bool));

#include <iostream>

class PrivateExists
{
private:
    int Method(bool);
    int* Test(int&, char);
};

class NotExists
{
};

int main()
{   
    std::cout << IsPrivateMethodMemberFunctionExists<PrivateExists>::value << std::endl;
    std::cout << IsMethodMemberFunctionExists<PrivateExists>::value << std::endl;

    //std::cout << IsPrivateMethodMemberFunctionExists<NotExists>::value << std::endl;
    //std::cout << IsMethodMemberFunctionExists<NotExists>::value << std::endl;
}

代码看起来是合法的,但是:

Clang Live将产生预期产出:

代码语言:javascript
复制
1
0

gcc Live

代码语言:javascript
复制
0
0

VC++ Live将而不是编译它。

嗯..。接下来的代码就会变得很奇怪:

代码语言:javascript
复制
int main()
{   
    std::cout << IsPrivateMethodMemberFunctionExists<PrivateExists>::value << std::endl;
    std::cout << IsMethodMemberFunctionExists<PrivateExists>::value << std::endl;

    std::cout << IsPrivateMethodMemberFunctionExists<NotExists>::value << std::endl;
    std::cout << IsMethodMemberFunctionExists<NotExists>::value << std::endl;
}

Clang Live

代码语言:javascript
复制
1
0
1
0

gcc Live

代码语言:javascript
复制
0
0
0
0

更新:我在重写以下内容时出错了:

代码语言:javascript
复制
class Exists
{
    void foo();
};

struct ITest
{
    virtual void foo() = 0;
};

class TestExists : Exists, ITest
{
};

TestExists不会覆盖foo(),所以它仍然是抽象的。解决办法是错误的。但是编译器的结果很有趣..。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29709037

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档