4

コンパイル時に、特定のスコープで公開されているかどうかに応じて、使用するタイプを選択しようとしています。コードに直接行くのが最善です:

#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, ::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, ::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, ::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、 には type があるため、 globalではLogなくそれを使用する必要があり、ない場合は global を使用する必要があるということです。現在、これらはどちらも関係なく機能します(このスコープでタイプがプライベートであるかどうかを確認するための私の間違ったテスト..)::LogB::Log1.

問題は にCありD、通常はテストなしでLog::log()失敗しAます。ただし、std::conditional<>が使用されている場合、コンパイル エラーは発生せず、接頭辞が であるため、出力は正しくありませんA:。それで、私が見逃したものは何ですか(間違ったテストを除いて-何らかの形で修正する必要があります...)?何もないとしても、合法的なものをA使用して私的タイプを公開するこのアプローチはありますか?std::conditional

編集:正気のために、私は以下でテストしました:

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

そして、それは global::Logを使用します。それが本当なら、何らかの形で private を使用してい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

この質問は今のところ開いたままにします..後で上記で閉じます。

4

1 に答える 1