[英]Why can you initialize a static const variable inline but not a plain static (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的更多詳細信息,請參閱下面的評論主題
#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.