0

boost::lexical_castは優れたツールですが、私のアプリケーションではstring -> bool変換の制限に遭遇し、私を悩ませていました。、 、 、 、"0"、 、"false"などのすべての文字列"FALSE"をに変換する必要があります。false"1""true""TRUE"true

boost::lexical_castとの間の変換のみをサポート"0""1"ます。だから私の考えは、うまくいくように見える私自身の変換関数を書くことでした:

bool str_to_bool(const std::string &str)
{
    if(str == "1" || str == "true" || str == "TRUE")
        return true;
    else if(str == "0" || str == "false" || str == "FALSE")
        return false;
    else
        throw std::runtime_error("Bad cast from std::string to bool!");
}

ここで、ラッパー ラウンドboost::lexical_castを作成し、独自のテンプレートの特殊化を作成したいと考えています。これが私がこれまでに得たものです:

template<typename Target, typename Source>
inline Target my_cast(const Source& src)
{
    return boost::lexical_cast<Target>(src);
}

template<>
inline bool my_cast(const std::string& src)
{
    return str_to_bool(src);
}

これは整数または std::string に対してはうまく機能しますが、文字列リテラルまたは文字ポインターに対しては明らかに失敗します。

int main(int argc, char* argv[])
{
    std::cout << my_cast<bool>(1) << std::endl;                    //OK
    std::cout << my_cast<bool>(std::string("true")) << std::endl;  //OK
    std::cout << my_cast<bool>("true") << std::endl;               //Fail! 

    return 0;
}

だから私は別の特殊化を書こうとしましchar *たが、コンパイルに失敗しました!

//does not compile!
template<>
inline bool my_cast(const char*& src)
{
    return str_to_bool(src);
}

std::string と の両方をサポートする正しい方法は何char *ですか?

編集 1: タイトルはばかげていた。修正しました。

EDIT 2:ブースト自体からソリューションを借りました。新しい回答として投稿されました。

4

4 に答える 4

2

あなたがこれを言うなら:

template<>
inline bool my_cast<bool, std::string>(std::string const & src)
{
  return str_to_bool(src);
}

template<>
inline bool my_cast<bool, const char *>(const char * const & src)
{
  return str_to_bool(src);
}

次に、少なくとも次の作業を行うことができます。

int main(int argc, char* argv[])
{
  const char * const q = "true";
  std::cout << my_cast<bool>(q) << std::endl;               //Fail!
  return 0;
}

更新:出来上がり:

typedef char FT[5];

template<>
inline bool my_cast<bool, FT>(const FT & src)
{
  return str_to_bool(src);
}
于 2011-07-02T21:25:34.210 に答える
2

これが機能するソリューションです。私はそれ自体からアイデアを得ましたboost::lexical_cast

template<class T>
struct array_to_pointer_decay
{
    typedef T type;
};

template<class T, std::size_t N>
struct array_to_pointer_decay<T[N]>
{
    typedef const T * type;
};

template<typename Target, typename Source>
Target my_cast_internal(const Source& s)
{
    return boost::lexical_cast<Target>(s);
}

template<>
inline bool my_cast_internal(const std::string& src)
{
    return str_to_bool(src);
}

template<>
inline bool my_cast_internal(const char* const& src)
{
    return str_to_bool(src);
}

template<typename Target, typename Source>
inline Target my_cast(const Source& s)
{
    typedef typename array_to_pointer_decay<Source>::type src;

    return my_cast_internal<Target, src>(s);
}

主な課題は、配列型を処理することです。は、array_to_pointer_decay任意の配列型を対応するポインター型に変換します。残りは簡単です。

于 2011-07-02T22:14:10.007 に答える
1

const char*ではなくを取る必要がありますconst char*&。ここでの変更可能な左辺値参照は左辺値にのみバインドされますが、文字列リテラルが実際に存在する配列型からの減衰は右辺値のみを生成し、const char*これには const 参照のみをバインドできます。

于 2011-07-02T21:17:27.790 に答える
1

これを新しい回答として追加させてください...タイプ消去バージョン!

C++98/03 の場合

/* Core caster */
bool str_to_bool(const std::string &str)
{
  if(str == "1" || str == "true" || str == "TRUE")
    return true;
  else if(str == "0" || str == "false" || str == "FALSE")
    return false;
  else
    throw std::runtime_error("Bad cast from std::string to bool!");
}


/* Type erasing scaffold */

struct TypeEraseBase
{
  virtual bool cast() const = 0;
  virtual ~TypeEraseBase() { }
};

template <typename T>
struct TypeEraseImpl : public TypeEraseBase
{
  TypeEraseImpl(const T & tt) : t(tt) { }
  virtual bool cast() const { return boost::lexical_cast<T>(t); }
private:
  const T & t;
};

/* Specializations go here */

template <>
struct TypeEraseImpl<std::string> : public TypeEraseBase
{
  TypeEraseImpl(const std::string & tt) : t(tt) { }
  virtual bool cast() const { return str_to_bool(t); }
private:
  const std::string & t;
};

template <size_t N>
struct TypeEraseImpl<char[N]> : public TypeEraseBase
{
  TypeEraseImpl(const char (& tt)[N]) : t(tt) { }
  virtual bool cast() const { return str_to_bool(std::string(t)); }
private:
  const char (& t)[N];
};

template <>
struct TypeEraseImpl<const char *> : public TypeEraseBase
{
  TypeEraseImpl(const char * const & tt) : t(tt) { }
  virtual bool cast() const { return str_to_bool(std::string(t)); }
private:
  const char * const & t;
};


/* User interface class */

struct my_cast
{
  template <typename T> my_cast(const T & tt)
  : pt(new TypeEraseImpl<T>(tt))
  {
  }

  ~my_cast() { if (pt) delete pt; }

  inline bool cast() const { return pt->cast(); }

private:
  const TypeEraseBase * const pt;
};


// Usage example

int main()
{
  const char * const q = "true";
  std::cout << my_cast(1).cast() << std::endl;
  std::cout << my_cast(std::string("true")).cast() << std::endl;
  std::cout << my_cast("true").cast() << std::endl;
  std::cout << my_cast(q).cast() << std::endl;

  return 0;
}

型特性バージョン、テンプレート化された戻り値の型

#include <string>
#include <stdexcept>
#include <iostream>
#include <ostream>
#include <boost/lexical_cast.hpp>

template <typename T> struct is_string : std::false_type { };
template <> struct is_string<std::string> : std::true_type { };
template <> struct is_string<const char *> : std::true_type { };
template <std::size_t N> struct is_string<char[N]> : std::true_type { };


/* The actual caster class */

template <typename T, bool B> struct to_bool
{
  static inline bool cast(const T & t)
  {
    return boost::lexical_cast<T>(t);
  }
};

template <typename T> struct to_bool<T, true>
{
  static inline bool cast(const T & t)
  {
    const std::string str(t);
    if(str == "1" || str == "true" || str == "TRUE")
      return true;
    else if(str == "0" || str == "false" || str == "FALSE")
      return false;
    else
      throw std::runtime_error("Bad cast from std::string to bool!");
  }
};


/* Type erasing helper class */

template <typename Target>
struct TypeEraseBase
{
  virtual Target cast() const = 0;
  virtual ~TypeEraseBase() { }
};

template <typename T, typename Target>
struct TypeEraseImpl : public TypeEraseBase<Target>
{
  TypeEraseImpl(const T & tt) : t(tt) { }
  virtual Target cast() const { return boost::lexical_cast<T>(t); }
private:
  const T & t;
};

template <typename T>
struct TypeEraseImpl<T, bool> : public TypeEraseBase<bool>
{
  TypeEraseImpl(const T & tt) : t(tt) { }
  virtual bool cast() const { return to_bool<T, is_string<T>::value>::cast(t); }
private:
  const T & t;
};


/* User interface class */

template <typename Target>
struct my_cast
{
  template <typename T> my_cast(const T & tt)
    : pt(new TypeEraseImpl<T, Target>(tt)) { }

  ~my_cast() { if (pt) delete pt; }

  inline Target cast() const { return pt->cast(); }

private:
  const TypeEraseBase<Target> * const pt;
};

template <typename Target>
std::ostream & operator<<(std::ostream & stream, const my_cast<Target> & c)
{ return stream << c.cast(); }


/* Usage */

int main()
{
  const char * const q = "true";
  std::cout << my_cast<bool>(1) << std::endl;
  std::cout << my_cast<bool>(std::string("true")) << std::endl;
  std::cout << my_cast<bool>("true") << std::endl;
  std::cout << my_cast<bool>(q) << std::endl;

  return 0;
}
于 2011-07-02T22:07:11.647 に答える