3

你知道如何对字符串执行惰性求值,就像在这个 D 片段中一样:

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

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

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

任何想法?谢谢你。

4

3 回答 3

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++,则必须小心不要在这些表达式中使用具有副作用(包括计算时间)的表达式。

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

对于简单的日志记录,宏就可以了。

于 2013-05-20T19:52:05.703 回答
3

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

你可以有一个类型,懒惰

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

然后你可以有一个 LAZY 包装器,它使用 lambda 创建其中一个

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

所有 my_lazy_type 需要的是一个接受 std::function 的构造函数,以及计算并返回 this 的 operator() 的重载。在每次评估中,您可以将 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;
}
于 2013-05-22T19:19:15.247 回答
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美分。

于 2013-05-20T20:17:27.173 回答