13

要するに問題: c ++11で提案された機能をプレーンなc++で
どのように実装できるでしょうか?static if

歴史と元々の問題:
最近、私はこのような問題を思いついた。Sender次のようなインターフェイスを持つクラスが必要です

class Sender
{
   void sendMessage( ... );
   void sendRequest( ... );
   void sendFile( ... );
   // lots of different send methods, not important actually
}

場合によっては、DoubleSender、つまりこのクラスのインスタンスを作成する必要があります。これは、そのメソッドを2回呼び出します。つまり、たとえばメソッドを呼び出すときはsendMessage(...)、同じメッセージを2回送信する必要があります。

私の解決策: 最初の
アプローチ:メンバーを用意し、各メソッド呼び出しの最後にチェックを行います
isDouble

sendMessage(...) { ... if( isDouble ) { sendMessage( ... ); }

ええと、私はこれを望んでいません。なぜなら、実際にはごく最近二重投稿が必要になり、タイムクリティカルセクションのコードのこの部分は98%パッシブになるからです。

2番目のアプローチ:から
クラスを継承し、次のようなメソッドを実装します。DoubleSenderSender

void DoubleSender::sendMessage( ... )
{
   Sender::sendMessage(...);
   Sender::sendMessage(...);
}

send..まあ、これは許容できますが、不快なコードの多くのスペースを必要とします(さまざまなメソッドがたくさんあるため、実際には多くのスペースが必要です。

3番目のアプローチ:
c++11を使用していると想像してください:)。次に、このクラスをジェネリックにし、次を使用して一時的な引数に従ってコードの必要な部分を生成できますstatic if

enum SenderType { Single, Double };
template<SenderType T>
class Sender
{
   void sendMessage(...)
   {
      // do stuff
      static if ( T == Single )
      {
         sendMessage(...);
      }
   }
};

これは以前のソリューションよりも短く、読みやすく、追加のコードを生成しません...それはc ++ 11ですが、残念ながら私の作業では使用できません。

だから、ここで私は私の質問に行き着きました-どうすればstatic ifc ++でアナログを実装できますか?
また、私の元の問題を解決する方法について他の提案をいただければ幸いです。
前もって感謝します。

4

4 に答える 4

9

@JohannesSchaubLitbを引用

gccで動作する私のstatic_ifでそれを行うことができます:)
いくつかの限られた方法で

(こちらもご覧ください

このトリックには、C++11のLambdasの仕様の特定のGCC解釈が含まれます。そのため、(おそらく)標準に対する欠陥レポートになります。これにより、このトリックは最新バージョンのGCCでは機能しなくなります(4.7ではすでに機能していません)。

Johannessの詳細については、以下のコメントスレッドを参照してください。

http://ideone.com/KytVv

#include <iostream>
 
namespace detail {
template<bool C>
struct call_if { template<typename F> void operator<<(F) { } };
 
template<>
struct call_if<true> {
  template<typename F>
  void operator<<(F f) { f(); }
};
}
 
#define static_if(cond) detail::call_if<cond>() << [&]
 
template<bool C, typename T>
void f(T t) {
  static_if(C) {
    t.foo();
  };
}
 
int main() {
  f<false>(42);
}
于 2012-03-30T10:22:33.793 に答える
7

送信の実装を送信者クラスのポリシーにして、CRTPを使用してみませんか。

template<class Derived>
class SingleSenderPolicy
{
    public:
    template< class memFunc >
    void callWrapperImpl(memFunc f, ...)
    {
        static_cast<Derived *>(this)->f(...);
    }
};

template< class Derived >
class DoubleSenderPolicy
{
    public:
    template< class memFunc >
    void callWrapperImpl(memFunc f, ...)
    {
        static_cast<Derived *>(this)->f(...);
        static_cast<Derived *>(this)->f(...);
     }
};

template< class SendPolicy>
class Sender : public SendPolicy< Sender >
{
public:
    void sendMessage( ... )
    {
       // call the policy to do the sending, passing in a member function that
       // acutally performs the action
       callWrapperImpl( &Sender::sendMessageImpl, ... );
    }

    void doSomethingElse( ... )
    {
       callWrapperImpl( &Sender::doSomethingElseImpl, ... );
    }


protected:
    void sendMessageImpl(... )
    {
        // Do the sending here
    } 

    void doSomethingElseImpl(... )
    {
        // Do the sending here
    } 
};

クラス内のパブリックsendXXX関数は、実際の機能を実装するメンバー関数を渡して、呼び出しラッパーに転送するだけです。SendPolicyこのメンバー関数は、クラスのに応じて呼び出されます。CRTPは、引数とこのポインターを呼び出すメンバー関数でラップするためのバインドの使用を節約します。

1つの関数では、コードの量を実際に削減することはできませんが、呼び出しが多い場合は役立つ可能性があります。

注:このコードは可能な解決策を提供するためのスケルトンであり、コンパイルされていません。

注:Sender<DoubleSenderPolicy>Sender<SingleSenderPolicy>は完全に異なるタイプであり、動的な継承関係を共有しません。

于 2012-03-30T15:00:44.257 に答える
5

ほとんどのコンパイラは定数畳み込みとデッドコードの削除を行うため、次のような通常のifステートメントを作成すると次のようになります。

enum SenderType { Single, Double };
template<SenderType T>
class Sender
{
   void sendMessage(...)
   {
      // do stuff
      if ( T == Single )
      {
         sendMessage(...);
      }
   }
};

コードが生成されると、ifブランチは削除されます。

必要なのstatic ifは、ステートメントがコンパイラエラーを引き起こす場合です。だからあなたがこのようなものを持っていたとしましょう(それはやや疑似コードです):

static if (it == random_access_iterator)
{
    it += n;
}

+=非ランダムアクセスイテレータを呼び出すことはできないため、デッドコードが削除された場合でも、コードは常に通常のifステートメントでコンパイルに失敗します。コンパイラは、コードを削除する前に構文をチェックするためです。コンパイラを使用static ifする場合、条件が真でない場合、構文のチェックをスキップします。

于 2012-04-03T21:28:21.077 に答える
0
std::string a("hello world");
// bool a = true;
if(std::is_same<std::string, decltype(a)>::value) {
    std::string &la = *(std::string*)&a;
    std::cout << "std::string " << la.c_str() << std::endl;
} else {
    bool &la = *(bool*)&a;
    std::cout << "other type" << std::endl;
}
于 2017-12-06T23:51:25.637 に答える