C ++中的懒惰11

时间:2013-05-20 19:48:24

标签: c++ c++11 d lazy-evaluation

你知道如何对字符串进行延迟评估,就像在这个D片段中一样:

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

实际上,问题可能根本不需要懒惰,因为 static if。也许有可能在不使用时丢弃char const*字符串?就像在C ++中一样:

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

有什么想法吗?谢谢。

3 个答案:

答案 0 :(得分: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 ++,则必须注意不要在这些表达式中使用带副作用的表达式(包括计算时间)。

要实现真正的懒惰,你必须实现记忆,这不是那么简单。

对于简单的日志记录,宏很好。

答案 1 :(得分:3)

您可以混合使用宏和lambda来创建此效果

你可以有一个类型,懒惰

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

然后你可以使用一个LAZY包装器,使用lambda

创建其中一个
#define LAZY(E) my_lazy_type<decltype((E))>([&](){ return E; })

所有my_lazy_type需求都是一个接受std :: function的构造函数,以及一个运算符()的重载,它会计算并返回它。在每次评估时,您可以使用只返回已计算值的thunk替换thunk,因此只会计算一次。

编辑: 这是我所说的一个例子。但我想指出这不是一个完美的例子。它在懒惰的一边传递了一堆东西,这可能完全打败了这一切的目的。它在内部使用mutable因为我需要能够在const情况下记忆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;
}

答案 2 :(得分: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美分。