加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 可以通过模板间接访问基类中的私有类型

发布时间:2020-12-16 07:05:15 所属栏目:百科 来源:网络整理
导读:我正在尝试在编译时选择要使用的类型,具体取决于是否在给定范围内公开可用.最好直接进入代码: #include iostream#include type_traitsclass Logger{ std::string _p;public: Logger(std::string p): _p(p) { } void say(std::string message) { std::cout _
我正在尝试在编译时选择要使用的类型,具体取决于是否在给定范围内公开可用.最好直接进入代码:

#include <iostream>
#include <type_traits>

class Logger
{
  std::string _p;
public:
  Logger(std::string p): _p(p)
  { }

  void say(std::string message)
  { std::cout << _p << ' ' << message << std::endl; }
};

struct Log
{
  static Logger& log()
  {
    static Logger _def("Default: ");
    return _def;
  }
};

// 1.
template <typename P>
struct use_logger
{
  static std::size_t test(P*);
  static char test(...);
  static const bool value = sizeof(test(reinterpret_cast<P*>(0))) == sizeof(std::size_t);
};

class A
{
  struct Log
  {
    static Logger& log()
    {
      static Logger _def("A: ");
      return _def;
    }
  };
public:

  void say()
  {
    std::cout << "A: " << use_logger<Log>::value << std::endl;
    std::conditional<use_logger<Log>::value,Log,::Log>::type::log().say("From A");
  }
};

class B
{
public:

  void say()
  {
    std::cout << "B: " << use_logger<Log>::value << std::endl;
    std::conditional<use_logger<Log>::value,::Log>::type::log().say("From B");
  }
};

class C : A
{
public:

  void say()
  {
    std::cout << "C: " << use_logger<Log>::value << std::endl;
    //2.
    std::conditional<use_logger<Log>::value,::Log>::type::log().say("From C");
    // Log::log().say("From C");
  }
};

class D : public A
{
public:

  void say()
  {
    // 2.
    std::cout << "D: " << use_logger<Log>::value << std::endl;
    std::conditional<use_logger<Log>::value,::Log>::type::log().say("From D");
    // Log::log().say("From C");
  }
};

int main(void)
{
  {
    A i;
    i.say();
  }
  {
    B i;
    i.say();
  }
  {
    C i;
    i.say();
  }
  {
    D i;
    i.say();
  }
}

我的意图是在A中,有一个类型的Log,所以应该使用而不是global :: Log,而在B中没有,它应该使用global :: Log.现在这两个工作都不管1.(我的错误测试,看看这个范围内的类型是否是私有的..)

问题出在C和D中,通常 – 没有测试,Log :: log()失败,因为它在A中是私有的.但是如果std :: conditional<>使用,没有编译错误,输出不正确,因为它以A:为前缀.所以,我错过了什么(除了不正确的测试 – 我需要以某种方式修复……)?如果没有,那么这种方法是使用std :: conditional legal暴露A中的私有类型吗?

编辑:为了理智,我测试了以下内容:

std::conditional<false,::Log>::type::log("From C");
std::conditional<false,::Log>::type::log("From D");

它确实使用了global :: Log,如果它是真的,它会以某种方式使用私有的A :: Log.

EDIT2:事实上,这似乎是一个更一般的条件,即您可以通过模板间接访问轻松访问某些内部私有类型,例如:

class F
{
  struct Foo
  {
    void bar() { }
  };
};

template <typename T>
struct ExposeInternal
{
  typedef T type;
};

int main(void)
{
  {
    // We've got Foo!
    ExposeInternal<F::Foo>::type t;
    t.bar();
  }
  {
    // Below fails
    F::Foo t;
    t.bar();
  }
}

编辑3:好的 – 已经确认,这是一个报告的GCC错误,与std :: conditional无关,尚未在4.7或4.8中修复. http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47346

我暂时将这个问题保持开放……稍后将关闭它.

解决方法

我已经修改了你的例子,所以w / my gcc 4.8.1现在一切都按预期工作(预期).

关于原始代码的几点注释:

>当你想测试Log的可访问性(使用use_logger)时,主要的误解是use_logger是A,B,C,D的外部类!它不能(通过设计)访问任何’cept公共成员的那些类!
>关于你的检查器的第二个方面:将类型Log传递给它,你将松开“上下文” – 即检查器不知道(并且没有办法实现它与那个设计)“这种类型是实际上是其他东西的嵌套类型?“
>最后use_logger只是不正确:它总是将0重新解释为P * – 没有其他可能性(解释方法)这个代码……这些检查器背后的主要思想是形成一组“匹配”函数,然后在实例化时,编译器将通过SFINAE删除不适当的(以及“回退”到通用测试(…)重载)或从结果重载集中接受一些最合适的.你的测试(P *)总是相关的! – 这就是为什么它实际上没有选择任何东西……

所以,这是我的代码:

#include <iostream>
#include <string>
#include <type_traits>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/identity.hpp>

class Logger
{
    std::string _p;
public:
    Logger(std::string p): _p(p)
    { }

    void say(std::string message)
    {
        std::cout << _p << ' ' << message << std::endl;
    }
};

struct Log
{
    static Logger& log()
    {
        static Logger _def("Default: ");
        return _def;
    }
};

namespace details {
/// Helper class to check availability of a nested type c Log
/// whithing c T and it's static function c log()
struct has_nested_logger_available_checker
{
    typedef char yes_type;
    typedef char (&no_type)[2];

    template <typename T>
    static no_type test(...);

    template <typename T>
    static yes_type test(
        typename std::add_pointer<
            decltype(std::is_same<decltype(T::Log::log()),Logger>::value,void())
        >::type
    );
};
}

/// Metafunction (type trait) to check is a nested type c Log accessible
template <typename T>
struct has_nested_logger_available : std::is_same<
    decltype(details::has_nested_logger_available_checker::template test<T>(nullptr)),details::has_nested_logger_available_checker::yes_type
>
{};

template <typename T>
struct access_nested_logger
{
    typedef typename T::Log type;
};

template <typename T>
struct logger_chooser : public boost::mpl::eval_if<
        has_nested_logger_available<T>,access_nested_logger<T>,boost::mpl::identity<::Log>
    >
{
};

class A
{
/// attention I suppose original code has a typo here:
/// anything in a c private section being inherited will be
/// b inaccessible to a child with c all kind of inheritance!
/// So if latter we want to use it from c D,it b must be at least
/// c protected.
protected:
    struct Log
    {
        static Logger& log()
        {
            static Logger _def("A: ");
            return _def;
        }
    };

    /// attention Checker and accessor c MUST be a friend of this class.
    /// Cuz being called from c A::say (which is actually a member,so it
    /// has full access to other members),it must have b the same access
    /// as other (say) member(s)!!!
    friend struct details::has_nested_logger_available_checker;
    /// todo Merge (actual) checker and "accessor" to the same class to
    /// reduce code to type... (a little)
    friend struct access_nested_logger<A>;

public:
    void say()
    {
        std::cout << "A: " << has_nested_logger_available<A>::value << std::endl;
        logger_chooser<A>::type::log().say("From A");
    }
};

class B
{
public:
    void say()
    {
        std::cout << "B: " << has_nested_logger_available<B>::value << std::endl;
        logger_chooser<B>::type::log().say("From B");
    }
};

class C : A
{
public:
    void say()
    {
        std::cout << "C: " << has_nested_logger_available<C>::value << std::endl;
        logger_chooser<C>::type::log().say("From C");
    }
};

/// With c public inharitance,c D can access c public and/or c protected
/// members of c A. But not c private !!!
class D : public A
{
public:
    /// sa c A
    friend struct details::has_nested_logger_available_checker;
    friend struct access_nested_logger<D>;

    void say()
    {
        std::cout << "D: " << has_nested_logger_available<D>::value << std::endl;
        logger_chooser<D>::type::log().say("From D");
    }
};

int main(void)
{
    {
        A i;
        i.say();
    }
    {
        B i;
        i.say();
    }
    {
        C i;
        i.say();
    }
    {
        D i;
        i.say();
    }
    return 0;
}

输出:

zaufi@gentop /work/tests $g++ -std=c++11 -o so_log_test so_log_test.cc
zaufi@gentop /work/tests $./so_log_test
A: 1
A:  From A
B: 0
Default:  From B
C: 0
Default:  From C
D: 1
A:  From D

zaufi@gentop /work/tests $g++ --version
g++ (Gentoo 4.8.1 p1.0,pie-0.5.6) 4.8.1
Copyright (C) 2013 Free Software Foundation,Inc.
This is free software
see the source for copying conditions.  There is NO
warranty
not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读