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 で遅延を実現するには、マクロとラムダ式の 2 つの方法があります。どちらも技術的には「遅延」ではありませんが、(「熱心な評価」ではなく) 「通常の評価」と呼ばれるものです。これは、式が何度でも評価される可能性があることを意味します。したがって、プログラムを D (または haskell) から C++ に変換する場合、これらの式で副作用 (計算時間を含む) を伴う式を使用しないように注意する必要があります。

真の怠惰を実現するには、メモ化を実装する必要がありますが、これはそれほど単純ではありません。

単純なロギングには、マクロで十分です。

于 2013-05-20T19:52:05.703 に答える
3

マクロとラムダを組み合わせてこの効果を作成できます

あなたは怠惰なタイプを持つことができます

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

そして、ラムダを使用してこれらのいずれかを作成するLAZYラッパーを作成できます

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

my_lazy_type に必要なのは、std::function を受け入れるコンストラクターと、これを評価して返す operator() のオーバーロードだけです。各評価で、既に計算された値を返すだけのサンクにサンクを置き換えることができるため、一度だけ計算されます。

編集:これは私が話していることの例です。ただし、これは完璧な例ではないことを指摘しておきます。それは、そもそもこれをすべて行う目的を完全に無効にする可能性のある怠惰な側で値によってたくさんのものを渡します。const の場合にサンクをメモできるようにする必要があるため、この内部でミュータブルを使用します。これは多くの点で改善される可能性がありますが、概念の適切な証明です。

#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 に答える