char 指针的模板特化?

发布于 2024-11-18 05:42:08 字数 1886 浏览 2 评论 0原文

boost::lexical_cast 是一个很棒的工具,但在我的应用程序中,我遇到了 string ->; 的限制。 bool 转换困扰着我。我需要将 "0""false""FALSE" 等所有字符串转换为 false 和 <将 code>"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:标题很愚蠢。修好了。

编辑2:我借用了boost本身的解决方案。作为新答案发布。

boost::lexical_cast is a great tool but in my application I ran into a limitation in string -> bool conversion that is bugging me. I need to convert all strings like "0", "false" and "FALSE" into false and "1", "true" and "TRUE" into true.

boost::lexical_cast only support conversion from/to "0" and "1". So my idea was to write my own conversion function which seems to work fine:

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!");
}

Now I wan to write a wrapper round boost::lexical_cast and write my own template specializations for it. Here is what I've got so far:

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);
}

This works great for integers or std::string but obviously fails for string literals or character pointers:

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;
}

So I tried to write another specialization for char * but it fails to compile!

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

What is the correct way to support both std::string and char *?

EDIT 1: the title was stupid. Fixed it.

EDIT 2: I borrowed a solution from boost itself. Posted as a new answer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

眼泪也成诗 2024-11-25 05:42:09

这是一个有效的解决方案。我从 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 将任何数组类型转换为相应的指针类型。现在剩下的就很容易了。

Here is a solution that works. I got the idea from boost::lexical_cast itself:

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);
}

The main challenge is to deal with array types. The array_to_pointer_decay converts any array type to the corresponding pointer type. The rest is easy now.

卸妝后依然美 2024-11-25 05:42:09

您需要使用 const char*,而不是 const char*&。这里的可变左值引用只会绑定到左值,而字符串文字实际所在的数组类型的衰减只会产生右值 const char*,您只能将 const 引用绑定到该右值。

You need to take a const char*, not a const char*&. The mutable lvalue reference here will only bind to an lvalue, whereas the decay from the array type that the string literal actually is will only produce an rvalue const char*, to which you can only bind a const reference.

凑诗 2024-11-25 05:42:09

让我将其添加为新答案......打字擦除版本!

对于 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;
}

Let me add this as a new answer... a type-erasing version!

For 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;
}

Type-traited version, templated return type

#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;
}
谈情不如逗狗 2024-11-25 05:42:08

如果你这样说:

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);
}

If you say this:

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);
}

Then at least you can make the following work:

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

Update: Voila:

typedef char FT[5];

template<>
inline bool my_cast<bool, FT>(const FT & src)
{
  return str_to_bool(src);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文