2

to_string(obj)作成するすべてのオブジェクト タイプに関数を提供したいと考えています。私はこの質問を見つけ、受け入れられた回答を適用しましたが、うまくいきました。ここまでは順調ですね。

次に、新しいタイプを作成しましたが、そのための を書くのto_string()を忘れていました (または、誤って ADL からアクセスできないようにしてしまいました)。問題は、私のプログラムはまだ正常にコンパイルされ、実行時に不明瞭なスタック オーバーフロー (TM) が発生することです。

代わりに、妥当なエラー メッセージを取得する方法はありますか?

この問題を示す小さなプログラムを次に示します。notstd::to_string()との間の無限再帰notstd::adl_helper::as_string()です。

#include <iostream>
#include <string>

namespace notstd {
  namespace adl_helper {
    using std::to_string;

    template<class T>
    std::string as_string( T&& t ) {
      return to_string( std::forward<T>(t) );
    }
  }
  template<class T>
  std::string to_string( T&& t ) {
    std::cout << "called" << std::endl; // <-- this is to show what's going on
    return adl_helper::as_string(std::forward<T>(t));
  }

  class A {
    /* both versions are needed, or the perfect forwarding candidate will
     * always be chosen by the compiler in case of a non-perfect match */
    //friend std::string to_string(A &a) { return std::string("a"); }
    //friend std::string to_string(const A &a) { return std::string("a"); }
  };
}


int main(int argc, char** argv) {

  notstd::A a;

  std::cout << to_string(a) << std::endl;
}

次のように、再帰防止チェックを実行するために使用する、もう 1 つのパラメーターを受け入れるラッパー関数を作成してみました。

#include <iostream>
#include <string>
#include <cassert>

namespace notstd {
  namespace wrap_std {
    std::string to_string(double v, bool) { return std::to_string(v); }
    /* .... etc.....  */
  }

  namespace adl_helper {
    using wrap_std::to_string;

    template<class T>
    std::string as_string( T&& t ) {
      return to_string( std::forward<T>(t), true );
    }
  }
  template<class T>
  std::string to_string( T&& t, bool recurring = false ) {
    std::cout << "called" << std::endl;
    assert(!recurring);
    return adl_helper::as_string(std::forward<T>(t));
  }

  class A {
    /* both versions are needed, or the perfect forwarding candidate will
     * always be chosen by the compiler in case of a non-perfect match */
    //friend std::string to_string(A &a) { return std::string("A"); }
    //friend std::string to_string(const A &a) { return std::string("A"); }
  };
}


int main(int argc, char** argv) {

  notstd::A a;

  std::cout << to_string(a) << std::endl;
}

ここでの問題は次のとおりです。

  • すべてのstd::to_string() オーバーロードをラップする必要があります
  • 実行時エラーのみが発生しますが、コンパイル時に問題を検出できるし、検出する必要があると感じています
  • 開発中にのみ役立つ何かのために、おそらくオーバーヘッドを追加しています。リリースモードでこれらすべてを無効にするマクロを追加することもできますが、さらに多くの作業が必要になります

テンプレートを使用してstd::to_string()、自分の型の特殊化をラップして作成することもできます...これはまったく別の獣ですが、適切な特殊化が利用できない場合、少なくともコンパイル時エラーが発生します。繰り返しになりますが、すべてのオーバーロードをラップする必要があり、std::to_string()少なくともすべてのコンパイラで c++20 がサポートされるまでは、おそらく (ほとんど) ADL を忘れる必要があります。

誰かがより良い解決策を持っていますか?

ありがとう!

4

1 に答える 1