簡體   English   中英

如果在普通的c ++中是靜態的?

[英]static if in plain c++?

問題簡而言之:
如何在c ++ 11中用普通c ++實現static if功能?

歷史和原始問題:
最近我提出了這樣的問題。 我需要一個類似於接口的類Sender

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

在某些情況下,我需要創建一個DoubleSender ,即這個類的一個實例,它會調用它的方法兩次,即在調用時,比方說sendMessage(...)方法,同樣的消息必須發送兩次。

我的解決方案
第一種方法:
有一個isDouble成員,並在每個方法調用結束時進行檢查

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

好吧,我不想要這個,因為實際上我最近需要雙重發布,這部分時間關鍵部分的代碼將是98%被動。

第二種方法:
Sender繼承一個類DoubleSender ,並實現其方法,如:

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

嗯,這是可以接受的,但需要很多不愉快的代碼空間(真的很多,因為有很多不同的send..方法。

第三種方法:
想象一下,我正在使用c ++ 11 :)。 然后我可以使這個類通用,並根據tempalte參數使用static if生成必要的代碼部分, static if

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

這比以前的解決方案更簡單,更容易閱讀,不會產生額外的代碼......它是c ++ 11,遺憾的是我無法在我的工作中使用它。

那么,這就是我提出問題的地方 - 如何在c ++中實現static if模擬?
此外,我將不勝感激任何其他有關如何解決我的原始問題的建議。
提前致謝。

引用@JohannesSchaubLitb

使用我的static_if可以在gcc上運行,可以做到:)
以某種有限的方式

(另見這里

這個技巧涉及GCC對C ++ 11中Lambdas規范的特定解釋。 因此,它(可能)將成為違反標准的缺陷報告。 這將導致該技巧不再適用於更新版本的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);
}

為什么不將send實現作為sender類的策略並使用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
    } 
};

您的類中的public sendXXX函數只需轉發到調用包裝器,傳入實現實際功能的成員函數。 將根據類的SendPolicy調用此成員函數。 CRTP保存使用bind來包裝參數,並使用成員函數調用此指針。

使用一個函數它並沒有真正減少代碼量,但如果你有很多調用它可以幫助。

注意:此代碼是提供可能解決方案的框架,尚未編譯。

注意: Sender<DoubleSenderPolicy>Sender<SingleSenderPolicy>是完全不同的類型,不共享動態繼承關系。

大多數編譯器會執行常量折疊和死代碼刪除,因此如果您編寫一個常規的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 ,如果條件不為真,編譯器將跳過檢查語法。

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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM