2013-05-20 132 views
3

你知道如何在這個d片斷執行字符串的懶惰評價,如:懶惰在C++ 11

void log(lazy string msg) { 
    static if (fooBarCondition) 
    writefln(…) /* something with msg */ 
} 

其實,這個問題可能不需要懶惰,因爲在所有的靜態如果。不使用時可能會丟棄char const*字符串?喜歡,在C++中:

void log(char const *msg) { 
    #ifdef DEBUG 
    cout << … << endl; /* something with msg */ 
    #else /* nothing at all */ 
    #endif 
} 

任何想法?謝謝。

+5

什麼? [[filler]] –

+1

做這樣的事情的最佳方法就是使用宏,以避免在不需要的情況下構建要傳遞的消息。 (參見'assert'宏) –

+1

使用'static if'看起來很吸引 –

回答

5
#ifdef DEBUG 
#define log(msg) do { cout << … << endl; } while(0) 
#else 
#define log(msg) do { } while(0) 
#endif 

有兩種方法可以在C++ 11中實現懶惰:宏和lambda表達式。技術上兩者不是「懶惰的」,而是所謂的「正常評估」(與「渴望評估」相反),這意味着可以多次評估表達式。因此,如果您將程序從D(或haskell)轉換爲C++,則必須注意不要在這些表達式中使用帶副作用的表達式(包括計算時間)。

要實現真正的懶惰,你將不得不實施記憶,這並不那麼簡單。

對於簡單的日誌記錄,宏只是很好。

+0

哦,只是一個宏呢?謝謝! – phaazon

+0

這就是獲得「懶惰評估」的方法,除非你想搗亂lambda。我不認爲你想爲伐木做這件事。 – Elazar

+0

是的,lambda對於只是日誌記錄而言是過分的。謝謝 – phaazon

0

儘管Elazar的答案有效,但我並不希望爲此使用宏(尤其是不包含所有小寫名稱的宏)。 這裏是我會做什麼,而不是:

template<bool /* = false */> 
struct logger_impl { 

    template<typename T> 
    static std::ostream & write(std::ostream & stream, T const &) { 
     return stream; 
    } 
}; 

template<> 
struct logger_impl<true> { 

    template<typename T> 
    static std::ostream & write(std::ostream & stream, T const & obj) { 
     return stream << obj; 
    } 
}; 

template<typename T> 
void log(T const & obj) { 
#if defined(NDEBUG) 
    logger_impl<true>::write(std::cout, obj); 
#else 
    logger_impl<false>::write(std::cout, obj); 
#endif 
} 

只是我的2美分。

+1

這IfThenElse模板是相當有用的,但它是*不*懶惰。即使未定義'NDEBUG',每次都會評估'log(exp)'*內部的表達式。 – Elazar

3

你可以混合宏和lambda表達式來產生這種效果

你可以有一個類型,懶惰

template<class T> 
class lazy { 
    ... 
} 

,然後你可以有一個使用Lambda

創建的其中一個慵懶的包裝
#define LAZY(E) my_lazy_type<decltype((E))>([&](){ return E; }) 

所有my_lazy_type需求都是一個接受std :: function的構造函數,以及一個operator()的重載函數,用於計算並返回它。在每次評估中,您可以用一個只返回已經計算的值的thunk替換該thunk,因此它只會計算一次。

編輯: 這裏是我正在談論的一個例子。不過,我想指出,這不是一個完美的例子。它通過價值在一堆懶散的東西中傳遞了一堆東西,這可能完全破壞了首先這樣做的目的。它內部使用可變內存,因爲我需要能夠在常量情況下記憶thunk。這可以在許多方面得到改善,但它是一個體面的概念證明。

#include <iostream> 
#include <functional> 
#include <memory> 
#include <string> 

#define LAZY(E) lazy<decltype((E))>{[&](){ return E; }} 

template<class T> 
class lazy { 
private: 
    struct wrapper { 
     std::function<T()> thunk; 
     wrapper(std::function<T()>&& x) 
      : thunk(std::move(x)) {} 
     wrapper(const std::function<T()>& x) 
      : thunk(x) {} 
    }; 
    //anytime I see mutable, I fill a bit odd 
    //this seems to be warented here however 
    mutable std::shared_ptr<wrapper> thunk_ptr; 
public: 
    lazy(std::function<T()>&& x) 
     : thunk_ptr(std::make_shared<wrapper>(std::move(x))) {} 
    T operator()() const { 
     T val = thunk_ptr->thunk(); 
     thunk_ptr->thunk = [val](){return val;}; 
     return val; 
    } 
}; 

void log(const lazy<std::string>& msg) { 
    std::cout << msg() << std::endl; 
} 

int main() { 
    std::string hello = "hello"; 
    std::string world = "world"; 
    log(LAZY(hello + ", " + world + "!")); 
    return 0; 
} 
+0

謝謝,但對於日誌記錄的東西,這是相當矯枉過正的,你不覺得嗎? – phaazon

+2

當然,它是過度的,我回答瞭如何達到懶惰的問題。如果你的目標只是記錄,我真的不明白你爲什麼需要懶惰。 – Jake

+0

@Jake爲什麼需要'wrapper'?不能只有'std :: shared_ptr'到'std :: function '? – Vahagn