2013-05-20 87 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