[英]Faking Static If in C++
我正在測試各種優化的組合,對於這些我需要靜態 - 如http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Static-If-I-Had-a-Hammer中所述並禁用特定的優化。 if(const-expr)並不總是有效,因為某些優化涉及更改數據布局,而這在功能范圍內無法完成。
基本上我想要的是這個:
template<bool enable_optimization>
class Algo{
struct Foo{
int a;
if(enable_optimization){
int b;
}
void bar(){
if(enable_optimization){
b = 0;
}
}
};
};
(是的,在我的情況下,從數據布局中刪除b的較小內存占用量是相關的。)
目前我正在使用非常糟糕的黑客偽裝它。 我正在尋找一種更好的方法。
檔案啊
#ifndef A_H
#define A_H
template<class enable_optimization>
class Algo;
#include "b.h"
#endif
文件bh(此文件是從Python腳本自動生成的)
#define ENABLE_OPTIMIZATION 0
#include "c.h"
#undef
#define ENABLE_OPTIMIZATION 1
#include "c.h"
#undef
文件ch
template<>
class Algo<ENABLE_OPTIMIZATION>{
struct Foo{
int a;
#if ENABLE_OPTIMIZATION
int b;
#endif
void bar(){
#if ENABLE_OPTIMIZATION
b = 0;
#endif
}
};
};
有誰知道更好的方法嗎? 從理論上講,它可以使用模板元編程完成,起初我使用它。 至少我使用它的方式是屁股的痛苦,並導致完全不可讀和臃腫的代碼。 使用上面的hack可以顯着提高生產力。
編輯:我有幾個優化標志,這些互動。
沒有理由使用模板使代碼變得更加復雜:
template<bool enable_optimization>
class FooOptimized
{
protected:
int b;
void bar_optim()
{
b = 0;
}
};
template<>
class FooOptimized<false>
{
protected:
void bar_optim() { }
};
template<bool enable_optimization>
struct Algo
{
struct Foo : FooOptimized<enable_optimization>
{
int a;
void bar()
{
this->bar_optim();
}
};
};
不需要元編程,只需根據優化是否啟用為新類型並將其專門化來區分不同的部分。
因為新類型在它為空時用作基類(即沒有FooOptimized::b
成員),所以它將不占用空間,因此sizeof(Algo<false>::Foo) == sizeof(int)
。
(可以隨意忽略這個答案的其余部分,它沒有直接解決問題,而是建議采用不同的方法進行不同的權衡。是否“更好”與否取決於真實代碼的細節,在問題中給出的小例子中沒有顯示。)
作為一個相關但又獨立的問題, Algo
和Algo::Foo
不依賴於是否啟用優化的部分仍然依賴於模板參數,因此盡管您只編寫一次這些代碼,編譯器將生成兩組目標代碼。 根據代碼中的工作量以及它的使用方式,您可能會發現將其更改為非模板代碼是有利的,即用動態多態替換靜態多態。 例如,您可以將enable_optimization
標志設置為運行時構造函數參數而不是模板參數:
struct FooImpl
{
virtual void bar() { }
};
class FooOptimized : FooImpl
{
int b;
void bar()
{
b = 0;
}
};
struct Algo
{
class Foo
{
std::unique_ptr<FooImpl> impl;
public:
explicit
Foo(bool optimize)
: impl(optimize ? new FooOptimized : new FooImpl)
{ }
int a;
void bar()
{
impl->bar();
}
};
};
您必須對其進行分析和測試,以確定虛擬函數的開銷是否比Algo
和Algo::Foo
中不依賴於模板參數的代碼重復更少。
注意:就目前而言,這種方法不起作用,因為在沒有為該成員分配空間的情況下似乎無法在類中擁有成員。 如果您知道如何使其工作,請隨時編輯。
你可以使用這樣的成語:
template<bool optimized, typename T> struct dbg_obj {
struct type {
// dummy operations so your code will compile using this type instead of T
template<typename U> type& operator=(const U&) { return *this; }
operator T&() { return *static_cast<T*>(0); /* this should never be executed! */ }
};
};
template<typename T> struct dbg_obj<false, T> {
typedef T type;
};
template<bool enable_optimization>
class Algo{
struct Foo{
int a;
typename dbg_obj<enable_optimization, int>::type b;
void bar(){
if(enable_optimization){
b = 0;
}
}
};
};
如果禁用了優化,則會為您提供正常的int
成員。 如果啟用了優化,則b
的類型是沒有成員的結構,不會占用任何空間。
當你的方法bar
使用什么看起來像一個運行時if
以決定是否要訪問b
,而不是像模板特明確編譯時的機制,你在使用操作b
必須從虛擬結構為好。 即使相關部分永遠不會被執行,並且編譯器很可能將它們優化掉,但首先是正確性檢查。 因此, b = 0
的行也必須為替換類型進行編譯。 這就是虛擬分配和虛擬投射操作的原因。 雖然兩者都足以滿足您的代碼需求,但我還是將它們包括在內,以防它們在某些其他方面證明是有用的,並且如果您需要它們,還可以了解如何添加更多代碼。
Jonathan Wakely提出的靜態解決方案(不是動態解決方案)是要走的路。
這個想法很簡單:
然后,為了不產生空間開銷,您可以通過繼承此特殊類的特化來利用EBO(空基優化)。
注意:一個屬性需要占用至少1個字節的空間,基類不在某些條件下(例如為空)。
在你的情況下:
b
是具體數據 所以我們可以輕松地構建一個類:
template <typename T> struct FooDependent;
template <>
struct FooDependent<true> {
int b;
void set(int x) { b = x; }
};
template <>
struct FooDependent<false> {
void set(int) {}
};
然后我們可以使用EBO將它注入Foo
:
struct Foo: FooDependent<enable_optimization> {
int a;
void bar() { this->set(0); }
};
注意:在模板化代碼中使用this
來訪問基類的成員,或者好的編譯器將拒絕您的代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.